From 5c4f6652e5395e86003396faf919dde3ee4a5b62 Mon Sep 17 00:00:00 2001 From: dphuang2 Date: Tue, 19 Nov 2024 17:41:02 -0800 Subject: [PATCH] fix anyof validation for python (#789) * fix anyof validation for python * all python tests work --- .../resources/python/exceptions.handlebars | 84 +++++------ .../main/resources/python/schemas.handlebars | 4 +- .../sdks/leap-workflows/api-fixed.json | 2 - .../sdks/python/leap_workflows/api_client.py | 3 + .../python/leap_workflows/configuration.py | 2 + .../sdks/python/leap_workflows/exceptions.py | 84 +++++------ .../leap_workflows/paths/v1_runs/post.py | 2 + .../leap_workflows/paths/v1_runs/post.pyi | 2 + .../paths/v1_runs_workflow_run_id/get.py | 2 + .../paths/v1_runs_workflow_run_id/get.pyi | 2 + .../sdks/python/leap_workflows/schemas.py | 72 ++++----- .../type/workflow_run_post_request.py | 1 + .../api_client.py | 21 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/post.py | 2 + .../paths/simple_endpoint/post.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 17 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 17 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python_async_default_timeout/schemas.py | 72 ++++----- .../api_client.py | 17 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../python/python_async_timeout/api_client.py | 17 ++- .../python_async_timeout/configuration.py | 2 + .../python/python_async_timeout/exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python/python_async_timeout/schemas.py | 72 ++++----- .../python/carbon/api_client.py | 140 +++++++++++++++++- .../python/carbon/configuration.py | 6 + .../python/carbon/exceptions.py | 84 +++++------ .../python/carbon/paths/add_webhook/post.py | 2 + .../python/carbon/paths/add_webhook/post.pyi | 2 + .../carbon/paths/auth_v1_access_token/get.py | 2 + .../carbon/paths/auth_v1_access_token/get.pyi | 2 + .../paths/auth_v1_white_labeling/get.py | 2 + .../paths/auth_v1_white_labeling/get.pyi | 2 + .../paths/create_user_file_tags/post.py | 2 + .../paths/create_user_file_tags/post.pyi | 2 + .../python/carbon/paths/delete_files/post.py | 2 + .../python/carbon/paths/delete_files/post.pyi | 2 + .../paths/delete_user_file_tags/post.py | 2 + .../paths/delete_user_file_tags/post.pyi | 2 + .../paths/delete_webhook_webhook_id/delete.py | 2 + .../delete_webhook_webhook_id/delete.pyi | 2 + .../carbon/paths/deletefile_file_id/delete.py | 2 + .../paths/deletefile_file_id/delete.pyi | 2 + .../python/carbon/paths/embeddings/post.py | 2 + .../python/carbon/paths/embeddings/post.pyi | 2 + .../python/carbon/paths/fetch_urls/get.py | 2 + .../python/carbon/paths/fetch_urls/get.pyi | 2 + .../paths/fetch_youtube_transcript/get.py | 2 + .../paths/fetch_youtube_transcript/get.pyi | 2 + .../python/carbon/paths/health/get.py | 2 + .../python/carbon/paths/health/get.pyi | 2 + .../integrations_confluence_list/post.py | 2 + .../integrations_confluence_list/post.pyi | 2 + .../integrations_confluence_sync/post.py | 2 + .../integrations_confluence_sync/post.pyi | 2 + .../paths/integrations_files_sync/post.py | 2 + .../paths/integrations_files_sync/post.pyi | 2 + .../paths/integrations_freshdesk/post.py | 2 + .../paths/integrations_freshdesk/post.pyi | 2 + .../paths/integrations_gmail_sync/post.py | 2 + .../paths/integrations_gmail_sync/post.pyi | 2 + .../integrations_gmail_user_labels/get.py | 2 + .../integrations_gmail_user_labels/get.pyi | 2 + .../paths/integrations_items_list/post.py | 2 + .../paths/integrations_items_list/post.pyi | 2 + .../paths/integrations_items_sync/post.py | 2 + .../paths/integrations_items_sync/post.pyi | 2 + .../paths/integrations_oauth_url/post.py | 2 + .../paths/integrations_oauth_url/post.pyi | 2 + .../paths/integrations_outlook_sync/post.py | 2 + .../paths/integrations_outlook_sync/post.pyi | 2 + .../integrations_outlook_user_folders/get.py | 2 + .../integrations_outlook_user_folders/get.pyi | 2 + .../paths/integrations_rss_feed/post.py | 2 + .../paths/integrations_rss_feed/post.pyi | 2 + .../carbon/paths/integrations_s3/post.py | 2 + .../carbon/paths/integrations_s3/post.pyi | 2 + .../paths/integrations_s3_files/post.py | 2 + .../paths/integrations_s3_files/post.pyi | 2 + .../paths/modify_user_configuration/post.py | 2 + .../paths/modify_user_configuration/post.pyi | 2 + .../python/carbon/paths/organization/get.py | 2 + .../python/carbon/paths/organization/get.pyi | 2 + .../carbon/paths/parsed_file_file_id/get.py | 2 + .../carbon/paths/parsed_file_file_id/get.pyi | 2 + .../carbon/paths/process_sitemap/get.py | 2 + .../carbon/paths/process_sitemap/get.pyi | 2 + .../carbon/paths/raw_file_file_id/get.py | 2 + .../carbon/paths/raw_file_file_id/get.pyi | 2 + .../python/carbon/paths/resync_file/post.py | 2 + .../python/carbon/paths/resync_file/post.pyi | 2 + .../carbon/paths/revoke_access_token/post.py | 2 + .../carbon/paths/revoke_access_token/post.pyi | 2 + .../carbon/paths/scrape_sitemap/post.py | 2 + .../carbon/paths/scrape_sitemap/post.pyi | 2 + .../python/carbon/paths/search_urls/get.py | 2 + .../python/carbon/paths/search_urls/get.pyi | 2 + .../python/carbon/paths/text_chunks/post.py | 2 + .../python/carbon/paths/text_chunks/post.pyi | 2 + .../upload_chunks_and_embeddings/post.py | 2 + .../upload_chunks_and_embeddings/post.pyi | 2 + .../carbon/paths/upload_file_from_url/post.py | 2 + .../paths/upload_file_from_url/post.pyi | 2 + .../python/carbon/paths/upload_text/post.py | 2 + .../python/carbon/paths/upload_text/post.pyi | 2 + .../python/carbon/paths/uploadfile/post.py | 2 + .../python/carbon/paths/uploadfile/post.pyi | 2 + .../python/carbon/paths/user/post.py | 2 + .../python/carbon/paths/user/post.pyi | 2 + .../carbon/paths/user_data_sources/post.py | 2 + .../carbon/paths/user_data_sources/post.pyi | 2 + .../python/carbon/paths/user_files/post.py | 2 + .../python/carbon/paths/user_files/post.pyi | 2 + .../python/carbon/paths/user_files_v2/post.py | 2 + .../carbon/paths/user_files_v2/post.pyi | 2 + .../python/carbon/paths/web_scrape/post.py | 2 + .../python/carbon/paths/web_scrape/post.pyi | 2 + .../python/carbon/paths/webhooks/post.py | 2 + .../python/carbon/paths/webhooks/post.pyi | 2 + .../python/carbon/schemas.py | 72 ++++----- .../chunks_and_embeddings_upload_input.py | 1 + .../type/embeddings_and_chunks_filters.py | 1 + .../type/embeddings_and_chunks_query_input.py | 1 + .../carbon/type/fresh_desk_connect_request.py | 1 + .../type/get_embedding_documents_body.py | 1 + .../python/carbon/type/gmail_sync_input.py | 1 + .../type/list_data_source_items_request.py | 1 + .../python/carbon/type/list_request.py | 1 + .../python/carbon/type/o_auth_url_request.py | 1 + .../python/carbon/type/outlook_sync_input.py | 1 + .../python/carbon/type/raw_text_input.py | 1 + .../carbon/type/resync_file_query_input.py | 1 + .../python/carbon/type/rss_feed_input.py | 1 + .../python/carbon/type/s3_file_sync_input.py | 1 + ...ngle_chunks_and_embeddings_upload_input.py | 1 + .../carbon/type/sitemap_scrape_request.py | 1 + .../python/carbon/type/sync_files_request.py | 1 + .../carbon/type/upload_file_from_url_input.py | 1 + .../python/carbon/type/webscrape_request.py | 1 + .../python-carbon/python/carbon/api_client.py | 140 +++++++++++++++++- .../python/carbon/configuration.py | 6 + .../python-carbon/python/carbon/exceptions.py | 84 +++++------ .../python/carbon/paths/add_webhook/post.py | 2 + .../python/carbon/paths/add_webhook/post.pyi | 2 + .../carbon/paths/auth_v1_access_token/get.py | 2 + .../carbon/paths/auth_v1_access_token/get.pyi | 2 + .../paths/auth_v1_white_labeling/get.py | 2 + .../paths/auth_v1_white_labeling/get.pyi | 2 + .../paths/create_user_file_tags/post.py | 2 + .../paths/create_user_file_tags/post.pyi | 2 + .../python/carbon/paths/delete_files/post.py | 2 + .../python/carbon/paths/delete_files/post.pyi | 2 + .../paths/delete_user_file_tags/post.py | 2 + .../paths/delete_user_file_tags/post.pyi | 2 + .../paths/delete_webhook_webhook_id/delete.py | 2 + .../delete_webhook_webhook_id/delete.pyi | 2 + .../carbon/paths/deletefile_file_id/delete.py | 2 + .../paths/deletefile_file_id/delete.pyi | 2 + .../python/carbon/paths/embeddings/post.py | 2 + .../python/carbon/paths/embeddings/post.pyi | 2 + .../python/carbon/paths/fetch_urls/get.py | 2 + .../python/carbon/paths/fetch_urls/get.pyi | 2 + .../paths/fetch_youtube_transcript/get.py | 2 + .../paths/fetch_youtube_transcript/get.pyi | 2 + .../python/carbon/paths/health/get.py | 2 + .../python/carbon/paths/health/get.pyi | 2 + .../integrations_confluence_list/post.py | 2 + .../integrations_confluence_list/post.pyi | 2 + .../integrations_confluence_sync/post.py | 2 + .../integrations_confluence_sync/post.pyi | 2 + .../paths/integrations_files_sync/post.py | 2 + .../paths/integrations_files_sync/post.pyi | 2 + .../paths/integrations_freshdesk/post.py | 2 + .../paths/integrations_freshdesk/post.pyi | 2 + .../paths/integrations_gmail_sync/post.py | 2 + .../paths/integrations_gmail_sync/post.pyi | 2 + .../integrations_gmail_user_labels/get.py | 2 + .../integrations_gmail_user_labels/get.pyi | 2 + .../paths/integrations_items_list/post.py | 2 + .../paths/integrations_items_list/post.pyi | 2 + .../paths/integrations_items_sync/post.py | 2 + .../paths/integrations_items_sync/post.pyi | 2 + .../paths/integrations_oauth_url/post.py | 2 + .../paths/integrations_oauth_url/post.pyi | 2 + .../paths/integrations_outlook_sync/post.py | 2 + .../paths/integrations_outlook_sync/post.pyi | 2 + .../integrations_outlook_user_folders/get.py | 2 + .../integrations_outlook_user_folders/get.pyi | 2 + .../paths/integrations_rss_feed/post.py | 2 + .../paths/integrations_rss_feed/post.pyi | 2 + .../carbon/paths/integrations_s3/post.py | 2 + .../carbon/paths/integrations_s3/post.pyi | 2 + .../paths/integrations_s3_files/post.py | 2 + .../paths/integrations_s3_files/post.pyi | 2 + .../paths/modify_user_configuration/post.py | 2 + .../paths/modify_user_configuration/post.pyi | 2 + .../python/carbon/paths/organization/get.py | 2 + .../python/carbon/paths/organization/get.pyi | 2 + .../carbon/paths/parsed_file_file_id/get.py | 2 + .../carbon/paths/parsed_file_file_id/get.pyi | 2 + .../carbon/paths/process_sitemap/get.py | 2 + .../carbon/paths/process_sitemap/get.pyi | 2 + .../carbon/paths/raw_file_file_id/get.py | 2 + .../carbon/paths/raw_file_file_id/get.pyi | 2 + .../python/carbon/paths/resync_file/post.py | 2 + .../python/carbon/paths/resync_file/post.pyi | 2 + .../carbon/paths/revoke_access_token/post.py | 2 + .../carbon/paths/revoke_access_token/post.pyi | 2 + .../carbon/paths/scrape_sitemap/post.py | 2 + .../carbon/paths/scrape_sitemap/post.pyi | 2 + .../python/carbon/paths/search_urls/get.py | 2 + .../python/carbon/paths/search_urls/get.pyi | 2 + .../python/carbon/paths/text_chunks/post.py | 2 + .../python/carbon/paths/text_chunks/post.pyi | 2 + .../upload_chunks_and_embeddings/post.py | 2 + .../upload_chunks_and_embeddings/post.pyi | 2 + .../carbon/paths/upload_file_from_url/post.py | 2 + .../paths/upload_file_from_url/post.pyi | 2 + .../python/carbon/paths/upload_text/post.py | 2 + .../python/carbon/paths/upload_text/post.pyi | 2 + .../python/carbon/paths/uploadfile/post.py | 2 + .../python/carbon/paths/uploadfile/post.pyi | 2 + .../python/carbon/paths/user/post.py | 2 + .../python/carbon/paths/user/post.pyi | 2 + .../carbon/paths/user_data_sources/post.py | 2 + .../carbon/paths/user_data_sources/post.pyi | 2 + .../python/carbon/paths/user_files/post.py | 2 + .../python/carbon/paths/user_files/post.pyi | 2 + .../python/carbon/paths/user_files_v2/post.py | 2 + .../carbon/paths/user_files_v2/post.pyi | 2 + .../python/carbon/paths/web_scrape/post.py | 2 + .../python/carbon/paths/web_scrape/post.pyi | 2 + .../python/carbon/paths/webhooks/post.py | 2 + .../python/carbon/paths/webhooks/post.pyi | 2 + .../python-carbon/python/carbon/schemas.py | 72 ++++----- .../chunks_and_embeddings_upload_input.py | 1 + .../type/embeddings_and_chunks_filters.py | 1 + .../type/embeddings_and_chunks_query_input.py | 1 + .../carbon/type/fresh_desk_connect_request.py | 1 + .../type/get_embedding_documents_body.py | 1 + .../python/carbon/type/gmail_sync_input.py | 1 + .../type/list_data_source_items_request.py | 1 + .../python/carbon/type/list_request.py | 1 + .../python/carbon/type/o_auth_url_request.py | 1 + .../python/carbon/type/outlook_sync_input.py | 1 + .../python/carbon/type/raw_text_input.py | 1 + .../carbon/type/resync_file_query_input.py | 1 + .../python/carbon/type/rss_feed_input.py | 1 + .../python/carbon/type/s3_file_sync_input.py | 1 + ...ngle_chunks_and_embeddings_upload_input.py | 1 + .../carbon/type/sitemap_scrape_request.py | 1 + .../python/carbon/type/sync_files_request.py | 1 + .../carbon/type/upload_file_from_url_input.py | 1 + .../python/carbon/type/webscrape_request.py | 1 + .../python_circular_reference_2/api_client.py | 19 ++- .../configuration.py | 2 + .../python_circular_reference_2/exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python_circular_reference_2/schemas.py | 72 ++++----- .../python_circular_reference/api_client.py | 20 ++- .../configuration.py | 2 + .../python_circular_reference/exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python_circular_reference/schemas.py | 72 ++++----- .../type/test_fetch_response.py | 1 + .../type/test_infinite_loop.py | 1 + .../sdks/python-decentro/python/.coverage | Bin 94208 -> 94208 bytes .../api_client.py | 37 ++++- .../configuration.py | 8 + .../exceptions.py | 84 +++++------ .../paths/v2_payments_collection/post.py | 2 + .../paths/v2_payments_collection/post.pyi | 2 + .../get.py | 2 + .../get.pyi | 2 + .../paths/v2_payments_upi_link/post.py | 2 + .../paths/v2_payments_upi_link/post.pyi | 2 + .../paths/v2_payments_upi_refund/post.py | 2 + .../paths/v2_payments_upi_refund/post.pyi | 2 + .../paths/v2_payments_vpa_validate/post.py | 2 + .../paths/v2_payments_vpa_validate/post.pyi | 2 + .../decentro_in_collections_client/schemas.py | 72 ++++----- .../type/generate_payment_link_request.py | 1 + .../type/issue_collect_request_request.py | 1 + .../type/issue_upi_refund_request.py | 1 + .../type/validate_upi_handle_request.py | 1 + .../python_enum_parameter/api_client.py | 18 ++- .../python_enum_parameter/configuration.py | 2 + .../python_enum_parameter/exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python/python_enum_parameter/schemas.py | 72 ++++----- .../api_client.py | 18 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../python_invalid_response/api_client.py | 26 +++- .../python_invalid_response/configuration.py | 2 + .../python_invalid_response/exceptions.py | 84 +++++------ .../dict_instead_of_list_or_scalar/get.py | 2 + .../dict_instead_of_list_or_scalar/get.pyi | 2 + .../paths/invalid_array/get.py | 2 + .../paths/invalid_array/get.pyi | 2 + .../paths/invalid_object/get.py | 2 + .../paths/invalid_object/get.pyi | 2 + .../paths/invalid_scalar/get.py | 2 + .../paths/invalid_scalar/get.pyi | 2 + .../paths/list_instead_of_scalar/get.py | 2 + .../paths/list_instead_of_scalar/get.pyi | 2 + .../paths/object_instead_of_scalar/get.py | 2 + .../paths/object_instead_of_scalar/get.pyi | 2 + .../paths/only_one_property_is_invalid/get.py | 2 + .../only_one_property_is_invalid/get.pyi | 2 + .../python/python_invalid_response/schemas.py | 72 ++++----- .../api_client.py | 19 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/post.py | 2 + .../paths/simple_endpoint/post.pyi | 2 + .../schemas.py | 72 ++++----- .../newscatcherapi_client/api_client.py | 55 ++++++- .../newscatcherapi_client/configuration.py | 2 + .../newscatcherapi_client/exceptions.py | 84 +++++------ .../paths/api_authors/get.py | 2 + .../paths/api_authors/get.pyi | 2 + .../paths/api_authors/post.py | 2 + .../paths/api_authors/post.pyi | 2 + .../paths/api_latest_headlines/get.py | 2 + .../paths/api_latest_headlines/get.pyi | 2 + .../paths/api_latest_headlines/post.py | 2 + .../paths/api_latest_headlines/post.pyi | 2 + .../paths/api_search/get.py | 2 + .../paths/api_search/get.pyi | 2 + .../paths/api_search/post.py | 2 + .../paths/api_search/post.pyi | 2 + .../paths/api_search_by_link/get.py | 2 + .../paths/api_search_by_link/get.pyi | 2 + .../paths/api_search_by_link/post.py | 2 + .../paths/api_search_by_link/post.pyi | 2 + .../paths/api_search_similar/get.py | 2 + .../paths/api_search_similar/get.pyi | 2 + .../paths/api_search_similar/post.py | 2 + .../paths/api_search_similar/post.pyi | 2 + .../paths/api_sources/get.py | 2 + .../paths/api_sources/get.pyi | 2 + .../paths/api_sources/post.py | 2 + .../paths/api_sources/post.pyi | 2 + .../paths/api_subscription/get.py | 2 + .../paths/api_subscription/get.pyi | 2 + .../paths/api_subscription/post.py | 2 + .../paths/api_subscription/post.pyi | 2 + .../python/newscatcherapi_client/schemas.py | 72 ++++----- .../sdks/python-newscatcher/python/.coverage | Bin 126976 -> 131072 bytes .../newscatcherapi_client/api_client.py | 57 ++++++- .../newscatcherapi_client/configuration.py | 2 + .../newscatcherapi_client/exceptions.py | 84 +++++------ .../paths/api_authors/get.py | 2 + .../paths/api_authors/get.pyi | 2 + .../paths/api_authors/post.py | 2 + .../paths/api_authors/post.pyi | 2 + .../paths/api_latest_headlines/get.py | 2 + .../paths/api_latest_headlines/get.pyi | 2 + .../paths/api_latest_headlines/post.py | 2 + .../paths/api_latest_headlines/post.pyi | 2 + .../paths/api_search/get.py | 2 + .../paths/api_search/get.pyi | 2 + .../paths/api_search/post.py | 2 + .../paths/api_search/post.pyi | 2 + .../paths/api_search_similar/get.py | 2 + .../paths/api_search_similar/get.pyi | 2 + .../paths/api_search_similar/post.py | 2 + .../paths/api_search_similar/post.pyi | 2 + .../paths/api_sources/get.py | 2 + .../paths/api_sources/get.pyi | 2 + .../paths/api_sources/post.py | 2 + .../paths/api_sources/post.pyi | 2 + .../paths/api_subscription/get.py | 2 + .../paths/api_subscription/get.pyi | 2 + .../paths/api_subscription/post.py | 2 + .../paths/api_subscription/post.pyi | 2 + .../python/newscatcherapi_client/schemas.py | 72 ++++----- .../type/author_search_request.py | 1 + .../type/clustering_search_response.py | 1 + ...s_author_search_response_article_result.py | 1 + ..._search_response_failed_search_response.py | 1 + ..._author_search_response_search_response.py | 1 + ...atest_headlines_response_article_result.py | 1 + ..._more_like_this_response_article_result.py | 1 + ...ke_this_response_failed_search_response.py | 1 + ...more_like_this_response_search_response.py | 1 + ...esponses_search_response_article_result.py | 1 + ..._search_response_failed_search_response.py | 1 + ...sponses_search_response_search_response.py | 1 + .../type/failed_latest_headlines_response.py | 1 + .../type/latest_headlines_response.py | 1 + .../type/more_like_this_request.py | 1 + .../type/search_request.py | 1 + .../type/subscription_response.py | 1 + .../exceptions.py | 84 +++++------ .../schemas.py | 4 +- .../api_client.py | 18 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 18 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 18 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 17 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python_pydantic_empty_response/schemas.py | 72 ++++----- .../python_pydantic_enum_str/api_client.py | 19 ++- .../python_pydantic_enum_str/configuration.py | 2 + .../python_pydantic_enum_str/exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python_pydantic_enum_str/schemas.py | 72 ++++----- .../api_client.py | 18 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 17 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 19 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python_pydantic_list_in_union/schemas.py | 72 ++++----- .../api_client.py | 19 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python_pydantic_list_response/schemas.py | 72 ++++----- .../api_client.py | 21 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 18 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 17 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 20 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/_list/get.py | 2 + .../paths/_list/get.pyi | 2 + .../paths/object/get.py | 2 + .../paths/object/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 19 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 21 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/attack_monster/post.py | 2 + .../paths/attack_monster/post.pyi | 2 + .../paths/retrieve_equipment/get.py | 2 + .../paths/retrieve_equipment/get.pyi | 2 + .../schemas.py | 72 ++++----- .../api_client.py | 18 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/test/get.py | 2 + .../paths/test/get.pyi | 2 + .../schemas.py | 72 ++++----- .../python/python_pydantic/api_client.py | 21 ++- .../python/python_pydantic/configuration.py | 2 + .../python/python_pydantic/exceptions.py | 84 +++++------ .../paths/reserved_word/get.py | 2 + .../paths/reserved_word/get.pyi | 2 + .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python/python_pydantic/schemas.py | 72 ++++----- .../api_client.py | 18 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../python_pydantic_union/api_client.py | 18 ++- .../python_pydantic_union/configuration.py | 2 + .../python_pydantic_union/exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python/python_pydantic_union/schemas.py | 72 ++++----- .../api_client.py | 17 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python_readme_header_snippet/schemas.py | 72 ++++----- .../python/snaptrade_client/api_client.py | 3 + .../python/snaptrade_client/configuration.py | 6 + .../python/snaptrade_client/exceptions.py | 84 +++++------ .../snaptrade_client/paths/accounts/get.py | 2 + .../snaptrade_client/paths/accounts/get.pyi | 2 + .../paths/accounts_account_id/get.py | 2 + .../paths/accounts_account_id/get.pyi | 2 + .../paths/accounts_account_id/put.py | 2 + .../paths/accounts_account_id/put.pyi | 2 + .../paths/accounts_account_id_balances/get.py | 2 + .../accounts_account_id_balances/get.pyi | 2 + .../paths/accounts_account_id_holdings/get.py | 2 + .../accounts_account_id_holdings/get.pyi | 2 + .../post.py | 2 + .../post.pyi | 2 + .../get.py | 2 + .../get.pyi | 2 + .../post.py | 2 + .../post.pyi | 2 + .../paths/accounts_account_id_options/get.py | 2 + .../paths/accounts_account_id_options/get.pyi | 2 + .../accounts_account_id_options_chain/get.py | 2 + .../accounts_account_id_options_chain/get.pyi | 2 + .../paths/accounts_account_id_orders/get.py | 2 + .../paths/accounts_account_id_orders/get.pyi | 2 + .../accounts_account_id_orders_cancel/post.py | 2 + .../post.pyi | 2 + .../accounts_account_id_positions/get.py | 2 + .../accounts_account_id_positions/get.pyi | 2 + .../paths/accounts_account_id_quotes/get.py | 2 + .../paths/accounts_account_id_quotes/get.pyi | 2 + .../paths/accounts_account_id_symbols/post.py | 2 + .../accounts_account_id_symbols/post.pyi | 2 + .../snaptrade_client/paths/activities/get.py | 2 + .../snaptrade_client/paths/activities/get.pyi | 2 + .../paths/authorizations/get.py | 2 + .../paths/authorizations/get.pyi | 2 + .../authorizations_authorization_id/delete.py | 2 + .../delete.pyi | 2 + .../authorizations_authorization_id/get.py | 2 + .../authorizations_authorization_id/get.pyi | 2 + .../brokerage_authorization_types/get.py | 2 + .../brokerage_authorization_types/get.pyi | 2 + .../snaptrade_client/paths/brokerages/get.py | 2 + .../snaptrade_client/paths/brokerages/get.pyi | 2 + .../snaptrade_client/paths/currencies/get.py | 2 + .../snaptrade_client/paths/currencies/get.pyi | 2 + .../paths/currencies_rates/get.py | 2 + .../paths/currencies_rates/get.pyi | 2 + .../currencies_rates_currency_pair/get.py | 2 + .../currencies_rates_currency_pair/get.pyi | 2 + .../snaptrade_client/paths/exchanges/get.py | 2 + .../snaptrade_client/paths/exchanges/get.pyi | 2 + .../snaptrade_client/paths/holdings/get.py | 2 + .../snaptrade_client/paths/holdings/get.pyi | 2 + .../paths/performance_custom/get.py | 2 + .../paths/performance_custom/get.pyi | 2 + .../python/snaptrade_client/paths/root/get.py | 2 + .../snaptrade_client/paths/root/get.pyi | 2 + .../paths/security_types/get.py | 2 + .../paths/security_types/get.pyi | 2 + .../paths/session_events/get.py | 2 + .../paths/session_events/get.pyi | 2 + .../paths/snap_trade_delete_user/delete.py | 2 + .../paths/snap_trade_delete_user/delete.pyi | 2 + .../paths/snap_trade_encrypted_jwt/get.py | 2 + .../paths/snap_trade_encrypted_jwt/get.pyi | 2 + .../paths/snap_trade_list_users/get.py | 2 + .../paths/snap_trade_list_users/get.pyi | 2 + .../paths/snap_trade_login/post.py | 2 + .../paths/snap_trade_login/post.pyi | 2 + .../paths/snap_trade_partners/get.py | 2 + .../paths/snap_trade_partners/get.pyi | 2 + .../paths/snap_trade_register_user/post.py | 2 + .../paths/snap_trade_register_user/post.pyi | 2 + .../snap_trade_reset_user_secret/post.py | 2 + .../snap_trade_reset_user_secret/post.pyi | 2 + .../snaptrade_client/paths/symbols/post.py | 2 + .../snaptrade_client/paths/symbols/post.pyi | 2 + .../paths/symbols_query/get.py | 2 + .../paths/symbols_query/get.pyi | 2 + .../paths/trade_impact/post.py | 2 + .../paths/trade_impact/post.pyi | 2 + .../snaptrade_client/paths/trade_oco/post.py | 2 + .../snaptrade_client/paths/trade_oco/post.pyi | 2 + .../paths/trade_place/post.py | 2 + .../paths/trade_place/post.pyi | 2 + .../paths/trade_trade_id/post.py | 2 + .../paths/trade_trade_id/post.pyi | 2 + .../sdks/python/snaptrade_client/schemas.py | 72 ++++----- .../snaptrade_client/type/options_symbol.py | 1 + .../type/options_symbol_nullable.py | 1 + .../snaptrade_client/type/universal_symbol.py | 1 + .../type/universal_symbol_nullable.py | 1 + .../python/python_typeddict/api_client.py | 3 + .../python/python_typeddict/configuration.py | 2 + .../python/python_typeddict/exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../python/python_typeddict/schemas.py | 72 ++++----- .../api_client.py | 21 ++- .../configuration.py | 2 + .../exceptions.py | 84 +++++------ .../paths/simple_endpoint/get.py | 2 + .../paths/simple_endpoint/get.pyi | 2 + .../schemas.py | 72 ++++----- .../python_splitit_client/api_client.py | 3 + .../python_splitit_client/exceptions.py | 84 +++++------ .../paths/api_installmentplans/post.py | 2 + .../paths/api_installmentplans/post.pyi | 2 + .../post.py | 2 + .../post.pyi | 2 + .../api_installmentplans_initiate/post.py | 2 + .../api_installmentplans_initiate/post.pyi | 2 + .../get.py | 2 + .../get.pyi | 2 + .../post.py | 2 + .../post.pyi | 2 + .../post.py | 2 + .../post.pyi | 2 + .../put.py | 2 + .../put.pyi | 2 + .../get.py | 2 + .../get.pyi | 2 + .../paths/api_installmentplans_search/get.py | 2 + .../paths/api_installmentplans_search/get.pyi | 2 + .../api_installmentplans_updateorder/put.py | 2 + .../api_installmentplans_updateorder/put.pyi | 2 + .../python/python_splitit_client/schemas.py | 72 ++++----- .../type/authorization_model.py | 1 + .../type/initiate_plan_response.py | 1 + .../python_splitit_client/type/installment.py | 1 + .../type/installment_plan_create_request.py | 1 + .../type/installment_plan_create_response.py | 1 + .../type/installment_plan_get_response.py | 1 + .../type/installment_plan_initiate_request.py | 1 + .../type/installment_plan_refund_request.py | 1 + .../type/installment_plan_update_response.py | 1 + .../type/payment_method_model.py | 1 + .../type/payment_plan_option_model.py | 1 + .../python_splitit_client/type/plan_data.py | 1 + .../type/plan_data_model.py | 1 + .../type/refund_model.py | 1 + .../search_installment_plan_response_item.py | 1 + .../type/verify_authorization_response.py | 1 + 692 files changed, 5318 insertions(+), 3358 deletions(-) diff --git a/generator/konfig-generator-api/src/main/resources/python/exceptions.handlebars b/generator/konfig-generator-api/src/main/resources/python/exceptions.handlebars index 3c277d75c..de39f6170 100644 --- a/generator/konfig-generator-api/src/main/resources/python/exceptions.handlebars +++ b/generator/konfig-generator-api/src/main/resources/python/exceptions.handlebars @@ -90,48 +90,6 @@ class ApiException(OpenApiException): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -182,3 +140,45 @@ class SchemaValidationError(OpenApiException): num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-generator-api/src/main/resources/python/schemas.handlebars b/generator/konfig-generator-api/src/main/resources/python/schemas.handlebars index 687f69905..dfe8b89e8 100644 --- a/generator/konfig-generator-api/src/main/resources/python/schemas.handlebars +++ b/generator/konfig-generator-api/src/main/resources/python/schemas.handlebars @@ -1870,7 +1870,7 @@ class ComposedBase(Discriminable): continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: {{#if nonCompliantUseDiscriminatorIfCompositionFails}} """ @@ -1929,7 +1929,7 @@ class ComposedBase(Discriminable): try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/api-fixed.json b/generator/konfig-integration-tests/sdks/leap-workflows/api-fixed.json index 0ca68193b..f35f749a7 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/api-fixed.json +++ b/generator/konfig-integration-tests/sdks/leap-workflows/api-fixed.json @@ -38,8 +38,6 @@ } ], "description": "This endpoint lets the user run a specified workflow with the provided workflow definition.", - "parameters": [ - ], "requestBody": { "required": true, "content": { diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/api_client.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/api_client.py index ceecb9ea9..fae908ded 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/api_client.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/api_client.py @@ -29,6 +29,8 @@ from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -52,6 +54,7 @@ unset, ) + @dataclass class MappedArgs: body: typing.Any = None diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/configuration.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/configuration.py index 15e4771d0..6c43a25f8 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/configuration.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/configuration.py @@ -139,6 +139,8 @@ def __init__(self, host=None, else: raise ClientConfigurationError('API Key "api_key" is required') if x_api_key: + if type(x_api_key) is not str: + raise ClientConfigurationError("x_api_key must be a string") self.api_key['api_key'] = x_api_key elif api_key is None: raise ClientConfigurationError('API Key "api_key" is required') diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/exceptions.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/exceptions.py index 9957d8551..ce7650ccc 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/exceptions.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.py index 0bfd28558..2bd8c556e 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.py @@ -353,6 +353,7 @@ def workflow( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint lets the user run a specified workflow with the provided workflow definition. """ args = self._workflow_mapped_args( workflow_id=workflow_id, webhook_url=webhook_url, @@ -395,6 +396,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint lets the user run a specified workflow with the provided workflow definition. """ args = self._workflow_mapped_args( workflow_id=workflow_id, webhook_url=webhook_url, diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.pyi b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.pyi index 58fedb7a0..faf866638 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.pyi +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs/post.pyi @@ -344,6 +344,7 @@ class Workflow(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint lets the user run a specified workflow with the provided workflow definition. """ args = self._workflow_mapped_args( workflow_id=workflow_id, webhook_url=webhook_url, @@ -386,6 +387,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint lets the user run a specified workflow with the provided workflow definition. """ args = self._workflow_mapped_args( workflow_id=workflow_id, webhook_url=webhook_url, diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.py index 7c2d1bc33..380c3aabf 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.py @@ -346,6 +346,7 @@ def get_workflow_run( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint retrieves the details of a specific workflow run using its `workflow_run_id`. """ args = self._get_workflow_run_mapped_args( workflow_run_id=workflow_run_id, ) @@ -380,6 +381,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint retrieves the details of a specific workflow run using its `workflow_run_id`. """ args = self._get_workflow_run_mapped_args( workflow_run_id=workflow_run_id, ) diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.pyi b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.pyi index cfbcc2d7c..4cb2796a7 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/paths/v1_runs_workflow_run_id/get.pyi @@ -337,6 +337,7 @@ class GetWorkflowRun(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint retrieves the details of a specific workflow run using its `workflow_run_id`. """ args = self._get_workflow_run_mapped_args( workflow_run_id=workflow_run_id, ) @@ -371,6 +372,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint retrieves the details of a specific workflow run using its `workflow_run_id`. """ args = self._get_workflow_run_mapped_args( workflow_run_id=workflow_run_id, ) diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/schemas.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/schemas.py index cfb09e624..11a4c8053 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/schemas.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/schemas.py @@ -975,6 +975,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1841,7 +1875,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1876,7 +1910,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1992,6 +2026,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2054,39 +2089,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/type/workflow_run_post_request.py b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/type/workflow_run_post_request.py index 6a2baa49b..9906f4708 100644 --- a/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/type/workflow_run_post_request.py +++ b/generator/konfig-integration-tests/sdks/leap-workflows/python-leap-workflows/sdks/python/leap_workflows/type/workflow_run_post_request.py @@ -21,6 +21,7 @@ class RequiredWorkflowRunPostRequest(TypedDict): # The UUID of the workflow to be run. workflow_id: str + class OptionalWorkflowRunPostRequest(TypedDict, total=False): # The URL to which the workflow results should be sent to on completion. webhook_url: str diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/api_client.py b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/api_client.py index 316b9ec4e..4798c4adf 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,13 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_allow_none_for_nullable_ref.pydantic.problematic_schema import ProblematicSchema +from python_allow_none_for_nullable_ref.pydantic.regular_object import RegularObject +from python_allow_none_for_nullable_ref.pydantic.regular_object_nullable import RegularObjectNullable +from python_allow_none_for_nullable_ref.pydantic.request_body import RequestBody + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +102,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +128,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +145,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/configuration.py b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/configuration.py index 9711b32cb..aaa1debf1 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/exceptions.py b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/exceptions.py index 7755ce8cf..47aa0288b 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.py b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.py index d86839909..51af04e95 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.py +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.py @@ -327,6 +327,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) @@ -391,6 +392,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.pyi b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.pyi index 35d625c23..8158c9e23 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/paths/simple_endpoint/post.pyi @@ -319,6 +319,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) @@ -383,6 +384,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) diff --git a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/schemas.py b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/schemas.py index c2ca176bc..873928782 100644 --- a/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-allow-none-for-nullable-ref/python/python_allow_none_for_nullable_ref/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/api_client.py b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/api_client.py index b07989916..061715e74 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/configuration.py b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/configuration.py index 2d5ad655a..b2c72ae77 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/exceptions.py b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/exceptions.py index 6bf8bf99b..375a55c31 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.py index f0d569c0e..af26d78bf 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.py @@ -261,6 +261,7 @@ def fetch( ) -> typing.Union[ api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -307,6 +308,7 @@ def get( ) -> typing.Union[ api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.pyi index 1736c4c4f..6035fdf17 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/paths/simple_endpoint/get.pyi @@ -253,6 +253,7 @@ class FetchRaw(BaseApi): ) -> typing.Union[ api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -299,6 +300,7 @@ class ApiForget(BaseApi): ) -> typing.Union[ api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/schemas.py b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/schemas.py index 6cf0f5293..1cf975f19 100644 --- a/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-api-exception-contains-response-headers/python/python_api_exception_contains_response_headers/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/api_client.py b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/api_client.py index a10873bf6..84404f50e 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/configuration.py b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/configuration.py index 9fa1f6e42..95321b485 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/exceptions.py b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/exceptions.py index 1db992503..afd2a9e3d 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.py index caf87b849..7c8f07a22 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.py @@ -265,6 +265,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.pyi index 2740154c2..76f8a3173 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/paths/simple_endpoint/get.pyi @@ -257,6 +257,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/schemas.py b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/schemas.py index 9e4ea0f7a..3bb0ad935 100644 --- a/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-async-default-timeout/python/python_async_default_timeout/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/api_client.py b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/api_client.py index fdb5ed220..9f1d59320 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/configuration.py b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/configuration.py index 1b0b2e319..4a4b715ad 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/exceptions.py b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/exceptions.py index 352c2cd5c..5e126a476 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.py index bdac0991e..2e44d5ee7 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.py @@ -265,6 +265,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.pyi index 3ef0410ec..c275767ba 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/paths/simple_endpoint/get.pyi @@ -257,6 +257,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/schemas.py b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/schemas.py index 13a8fd280..b351748bf 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout-with-top-level-operation/python/python_async_timeout_with_top_level_operation/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/api_client.py b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/api_client.py index 28c9f5ba1..6d13df74d 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/configuration.py b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/configuration.py index 906c04a69..27e08a2f4 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/exceptions.py b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/exceptions.py index bb50e9558..8b14b63de 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.py index 282485315..15a089b55 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.py @@ -265,6 +265,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.pyi index fa3a5ff74..f6ce9d8af 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/paths/simple_endpoint/get.pyi @@ -257,6 +257,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/schemas.py b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/schemas.py index cb7dee4fb..ae89c9be5 100644 --- a/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-async-timeout/python/python_async_timeout/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/api_client.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/api_client.py index be50c2807..1dcf12b47 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/api_client.py @@ -24,11 +24,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -52,6 +55,132 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from carbon.pydantic.add_webhook_props import AddWebhookProps +from carbon.pydantic.body_create_upload_file_uploadfile_post import BodyCreateUploadFileUploadfilePost +from carbon.pydantic.chunk_properties import ChunkProperties +from carbon.pydantic.chunk_properties_nullable import ChunkPropertiesNullable +from carbon.pydantic.chunks_and_embeddings import ChunksAndEmbeddings +from carbon.pydantic.chunks_and_embeddings_embedding import ChunksAndEmbeddingsEmbedding +from carbon.pydantic.chunks_and_embeddings_upload_input import ChunksAndEmbeddingsUploadInput +from carbon.pydantic.configuration_keys import ConfigurationKeys +from carbon.pydantic.data_source_last_sync_actions import DataSourceLastSyncActions +from carbon.pydantic.data_source_sync_statuses import DataSourceSyncStatuses +from carbon.pydantic.data_source_type import DataSourceType +from carbon.pydantic.data_source_type_nullable import DataSourceTypeNullable +from carbon.pydantic.delete_files_query_input import DeleteFilesQueryInput +from carbon.pydantic.delete_files_query_input_file_ids import DeleteFilesQueryInputFileIds +from carbon.pydantic.directory_item import DirectoryItem +from carbon.pydantic.document_response import DocumentResponse +from carbon.pydantic.document_response_list import DocumentResponseList +from carbon.pydantic.document_response_tags import DocumentResponseTags +from carbon.pydantic.document_response_vector import DocumentResponseVector +from carbon.pydantic.embedding_and_chunk import EmbeddingAndChunk +from carbon.pydantic.embedding_and_chunk_embedding import EmbeddingAndChunkEmbedding +from carbon.pydantic.embedding_generators import EmbeddingGenerators +from carbon.pydantic.embedding_generators_nullable import EmbeddingGeneratorsNullable +from carbon.pydantic.embedding_properties import EmbeddingProperties +from carbon.pydantic.embeddings_and_chunks_filters import EmbeddingsAndChunksFilters +from carbon.pydantic.embeddings_and_chunks_order_by_columns import EmbeddingsAndChunksOrderByColumns +from carbon.pydantic.embeddings_and_chunks_query_input import EmbeddingsAndChunksQueryInput +from carbon.pydantic.embeddings_and_chunks_response import EmbeddingsAndChunksResponse +from carbon.pydantic.external_file_sync_statuses import ExternalFileSyncStatuses +from carbon.pydantic.external_source_item import ExternalSourceItem +from carbon.pydantic.fetch_urls_response import FetchURLsResponse +from carbon.pydantic.fetch_urls_response_urls import FetchURLsResponseUrls +from carbon.pydantic.file_content_types import FileContentTypes +from carbon.pydantic.file_content_types_nullable import FileContentTypesNullable +from carbon.pydantic.file_formats import FileFormats +from carbon.pydantic.file_formats_nullable import FileFormatsNullable +from carbon.pydantic.file_statistics import FileStatistics +from carbon.pydantic.file_statistics_nullable import FileStatisticsNullable +from carbon.pydantic.files_query_user_files_deprecated_response import FilesQueryUserFilesDeprecatedResponse +from carbon.pydantic.fresh_desk_connect_request import FreshDeskConnectRequest +from carbon.pydantic.generic_success_response import GenericSuccessResponse +from carbon.pydantic.get_embedding_documents_body import GetEmbeddingDocumentsBody +from carbon.pydantic.get_embedding_documents_body_file_ids import GetEmbeddingDocumentsBodyFileIds +from carbon.pydantic.get_embedding_documents_body_parent_file_ids import GetEmbeddingDocumentsBodyParentFileIds +from carbon.pydantic.get_embedding_documents_body_query_vector import GetEmbeddingDocumentsBodyQueryVector +from carbon.pydantic.get_embedding_documents_body_tags import GetEmbeddingDocumentsBodyTags +from carbon.pydantic.gmail_sync_input import GmailSyncInput +from carbon.pydantic.http_validation_error import HTTPValidationError +from carbon.pydantic.hybrid_search_tuning_params import HybridSearchTuningParams +from carbon.pydantic.hybrid_search_tuning_params_nullable import HybridSearchTuningParamsNullable +from carbon.pydantic.list_data_source_items_request import ListDataSourceItemsRequest +from carbon.pydantic.list_data_source_items_response import ListDataSourceItemsResponse +from carbon.pydantic.list_request import ListRequest +from carbon.pydantic.list_response import ListResponse +from carbon.pydantic.modify_user_configuration_input import ModifyUserConfigurationInput +from carbon.pydantic.o_auth_url_request import OAuthURLRequest +from carbon.pydantic.order_dir import OrderDir +from carbon.pydantic.organization_response import OrganizationResponse +from carbon.pydantic.organization_user_data_source_api import OrganizationUserDataSourceAPI +from carbon.pydantic.organization_user_data_source_filters import OrganizationUserDataSourceFilters +from carbon.pydantic.organization_user_data_source_filters_ids import OrganizationUserDataSourceFiltersIds +from carbon.pydantic.organization_user_data_source_order_by_columns import OrganizationUserDataSourceOrderByColumns +from carbon.pydantic.organization_user_data_source_query_input import OrganizationUserDataSourceQueryInput +from carbon.pydantic.organization_user_data_source_response import OrganizationUserDataSourceResponse +from carbon.pydantic.organization_user_file_tag_create import OrganizationUserFileTagCreate +from carbon.pydantic.organization_user_file_tag_create_tags import OrganizationUserFileTagCreateTags +from carbon.pydantic.organization_user_file_tags_remove import OrganizationUserFileTagsRemove +from carbon.pydantic.organization_user_file_tags_remove_tags import OrganizationUserFileTagsRemoveTags +from carbon.pydantic.organization_user_files_to_sync_filters import OrganizationUserFilesToSyncFilters +from carbon.pydantic.organization_user_files_to_sync_filters_external_file_ids import OrganizationUserFilesToSyncFiltersExternalFileIds +from carbon.pydantic.organization_user_files_to_sync_filters_ids import OrganizationUserFilesToSyncFiltersIds +from carbon.pydantic.organization_user_files_to_sync_filters_organization_user_data_source_id import OrganizationUserFilesToSyncFiltersOrganizationUserDataSourceId +from carbon.pydantic.organization_user_files_to_sync_filters_parent_file_ids import OrganizationUserFilesToSyncFiltersParentFileIds +from carbon.pydantic.organization_user_files_to_sync_filters_tags import OrganizationUserFilesToSyncFiltersTags +from carbon.pydantic.organization_user_files_to_sync_order_by_types import OrganizationUserFilesToSyncOrderByTypes +from carbon.pydantic.organization_user_files_to_sync_query_input import OrganizationUserFilesToSyncQueryInput +from carbon.pydantic.outlook_sync_input import OutlookSyncInput +from carbon.pydantic.pagination import Pagination +from carbon.pydantic.presigned_url_response import PresignedURLResponse +from carbon.pydantic.rss_feed_input import RSSFeedInput +from carbon.pydantic.raw_text_input import RawTextInput +from carbon.pydantic.resync_file_query_input import ResyncFileQueryInput +from carbon.pydantic.revoke_access_token_input import RevokeAccessTokenInput +from carbon.pydantic.s3_auth_request import S3AuthRequest +from carbon.pydantic.s3_file_sync_input import S3FileSyncInput +from carbon.pydantic.s3_get_file_input import S3GetFileInput +from carbon.pydantic.single_chunks_and_embeddings_upload_input import SingleChunksAndEmbeddingsUploadInput +from carbon.pydantic.sitemap_scrape_request import SitemapScrapeRequest +from carbon.pydantic.sitemap_scrape_request_css_classes_to_skip import SitemapScrapeRequestCssClassesToSkip +from carbon.pydantic.sitemap_scrape_request_css_selectors_to_skip import SitemapScrapeRequestCssSelectorsToSkip +from carbon.pydantic.sitemap_scrape_request_html_tags_to_skip import SitemapScrapeRequestHtmlTagsToSkip +from carbon.pydantic.sitemap_scrape_request_tags import SitemapScrapeRequestTags +from carbon.pydantic.sync_directory_request import SyncDirectoryRequest +from carbon.pydantic.sync_files_request import SyncFilesRequest +from carbon.pydantic.sync_files_request_ids import SyncFilesRequestIds +from carbon.pydantic.text_embedding_generators import TextEmbeddingGenerators +from carbon.pydantic.token_response import TokenResponse +from carbon.pydantic.upload_file_from_url_input import UploadFileFromUrlInput +from carbon.pydantic.user_file import UserFile +from carbon.pydantic.user_file_embedding_properties import UserFileEmbeddingProperties +from carbon.pydantic.user_files_v2 import UserFilesV2 +from carbon.pydantic.user_request_content import UserRequestContent +from carbon.pydantic.user_response import UserResponse +from carbon.pydantic.user_response_unique_file_tags import UserResponseUniqueFileTags +from carbon.pydantic.utilities_scrape_web_request import UtilitiesScrapeWebRequest +from carbon.pydantic.validation_error import ValidationError +from carbon.pydantic.validation_error_loc import ValidationErrorLoc +from carbon.pydantic.webhook import Webhook +from carbon.pydantic.webhook_filters import WebhookFilters +from carbon.pydantic.webhook_filters_ids import WebhookFiltersIds +from carbon.pydantic.webhook_no_key import WebhookNoKey +from carbon.pydantic.webhook_order_by_columns import WebhookOrderByColumns +from carbon.pydantic.webhook_query_input import WebhookQueryInput +from carbon.pydantic.webhook_query_response import WebhookQueryResponse +from carbon.pydantic.webscrape_request import WebscrapeRequest +from carbon.pydantic.webscrape_request_css_classes_to_skip import WebscrapeRequestCssClassesToSkip +from carbon.pydantic.webscrape_request_css_selectors_to_skip import WebscrapeRequestCssSelectorsToSkip +from carbon.pydantic.webscrape_request_html_tags_to_skip import WebscrapeRequestHtmlTagsToSkip +from carbon.pydantic.webscrape_request_tags import WebscrapeRequestTags +from carbon.pydantic.white_labeling_response import WhiteLabelingResponse +from carbon.pydantic.youtube_transcript_response import YoutubeTranscriptResponse +from carbon.pydantic.youtube_transcript_response_raw_transcript import YoutubeTranscriptResponseRawTranscript +from carbon.pydantic.youtube_transcript_response_raw_transcript_item import YoutubeTranscriptResponseRawTranscriptItem + @dataclass class MappedArgs: body: typing.Any = None @@ -91,7 +220,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -117,6 +246,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -131,12 +263,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/configuration.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/configuration.py index e81ca743c..84710af09 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/configuration.py @@ -132,10 +132,16 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if access_token: + if type(access_token) is not str: + raise ClientConfigurationError("access_token must be a string") self.api_key['accessToken'] = access_token if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['apiKey'] = api_key if customer_id: + if type(customer_id) is not str: + raise ClientConfigurationError("customer_id must be a string") self.api_key['customerId'] = customer_id """dict to store API key(s) """ diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/exceptions.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/exceptions.py index a2106ba54..af955b055 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/exceptions.py @@ -97,48 +97,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -189,3 +147,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.py index c3ba452cb..45d124edf 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.py @@ -351,6 +351,7 @@ def add_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) @@ -415,6 +416,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.pyi index 3f66aa769..2caf7ddfc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/add_webhook/post.pyi @@ -342,6 +342,7 @@ class AddUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.py index a085fc4c8..86986bf38 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.py @@ -294,6 +294,7 @@ def get_access_token( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( @@ -348,6 +349,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.pyi index 76b358eab..b4d4d42ae 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_access_token/get.pyi @@ -283,6 +283,7 @@ class GetAccessTokenRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.py index 8fc9f8c33..7f4b8433a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.py @@ -292,6 +292,7 @@ def get_white_labeling( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( @@ -346,6 +347,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.pyi index b7861ddac..491607325 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/auth_v1_white_labeling/get.pyi @@ -283,6 +283,7 @@ class GetWhiteLabelingRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.py index c04675dff..b3b4a0c73 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.py @@ -362,6 +362,7 @@ def create_user_file_tags( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -434,6 +435,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.pyi index 69a4322a9..f11dc5a55 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/create_user_file_tags/post.pyi @@ -351,6 +351,7 @@ class CreateUserFileTagsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -423,6 +424,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.py index 235abc725..a93ce587e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.py @@ -371,6 +371,7 @@ def delete_many( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, @@ -451,6 +452,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.pyi index 182f67b86..a0d4cb6bf 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_files/post.pyi @@ -360,6 +360,7 @@ class DeleteManyRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, @@ -440,6 +441,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.py index edce34b47..0cde98e54 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.py @@ -362,6 +362,7 @@ def delete_file_tags( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -434,6 +435,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.pyi index 346b07e75..ed024015c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_user_file_tags/post.pyi @@ -351,6 +351,7 @@ class DeleteFileTagsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -423,6 +424,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.py index e9557430b..0e57727ad 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.py @@ -357,6 +357,7 @@ def delete_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) @@ -421,6 +422,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.pyi index fdca5fbb5..bf0ec9856 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/delete_webhook_webhook_id/delete.pyi @@ -348,6 +348,7 @@ class DeleteUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) @@ -412,6 +413,7 @@ class ApiFordelete(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.py index 7910ff35f..47ef692d5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.py @@ -359,6 +359,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) @@ -423,6 +424,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.pyi index 26697b2ed..194d82324 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/deletefile_file_id/delete.pyi @@ -348,6 +348,7 @@ class DeleteRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) @@ -412,6 +413,7 @@ class ApiFordelete(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.py index cda04a502..a98428a48 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.py @@ -452,6 +452,7 @@ def get_documents( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, @@ -620,6 +621,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.pyi index 82f31cf3e..f5c39b652 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/embeddings/post.pyi @@ -441,6 +441,7 @@ class GetDocumentsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, @@ -609,6 +610,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.py index fa43720b0..185746613 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.py @@ -362,6 +362,7 @@ def fetch_urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) @@ -426,6 +427,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.pyi index c16ed4320..7da5391d1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_urls/get.pyi @@ -351,6 +351,7 @@ class FetchUrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) @@ -415,6 +416,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.py index e1f1aeedc..9102ce93a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.py @@ -378,6 +378,7 @@ def fetch_youtube_transcripts( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, @@ -450,6 +451,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.pyi index 4dc01c1bd..1210d71a6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/fetch_youtube_transcript/get.pyi @@ -367,6 +367,7 @@ class FetchYoutubeTranscriptsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, @@ -439,6 +440,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.py index 6188e3d6d..68be5b43a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.py @@ -257,6 +257,7 @@ def check( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( @@ -311,6 +312,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.pyi index b93a5cef8..c37513c8c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/health/get.pyi @@ -252,6 +252,7 @@ class CheckRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( @@ -306,6 +307,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.py index ce14dd256..15556cccc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.py @@ -359,6 +359,7 @@ def list_confluence_pages( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.pyi index dceff6d8c..96a5fe2cc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_list/post.pyi @@ -348,6 +348,7 @@ class ListConfluencePagesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.py index f066d09a7..2cc9d4037 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.py @@ -413,6 +413,7 @@ def sync_confluence( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, @@ -549,6 +550,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.pyi index dae7c5783..4e8f234c7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_confluence_sync/post.pyi @@ -402,6 +402,7 @@ class SyncConfluenceRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, @@ -538,6 +539,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.py index 03315198a..1d254ec9f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.py @@ -413,6 +413,7 @@ def sync_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, @@ -549,6 +550,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.pyi index 0218b421a..5ac5a8d90 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_files_sync/post.pyi @@ -402,6 +402,7 @@ class SyncFilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, @@ -538,6 +539,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.py index e95129f3e..438d321a7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.py @@ -404,6 +404,7 @@ def connect_freshdesk( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, @@ -532,6 +533,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.pyi index fc60b7430..c4131669a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_freshdesk/post.pyi @@ -393,6 +393,7 @@ class ConnectFreshdeskRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, @@ -521,6 +522,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.py index 5f29f72f1..462fee83a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.py @@ -398,6 +398,7 @@ def sync_gmail( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.pyi index bd24219b0..a5c539360 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_sync/post.pyi @@ -387,6 +387,7 @@ class SyncGmailRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.py index 1553396f3..82b93e8c6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.py @@ -291,6 +291,7 @@ def list_labels( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( @@ -345,6 +346,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.pyi index 574e8e2f2..d4808e001 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_gmail_user_labels/get.pyi @@ -280,6 +280,7 @@ class ListLabelsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( @@ -334,6 +335,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.py index 7b86208e5..06d19008b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.py @@ -368,6 +368,7 @@ def list_data_source_items( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -448,6 +449,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.pyi index 9ada873e5..b527a3dca 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_list/post.pyi @@ -357,6 +357,7 @@ class ListDataSourceItemsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -437,6 +438,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.py index 3bc22043d..6c241127f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.py @@ -353,6 +353,7 @@ def sync_data_source_items( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) @@ -417,6 +418,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.pyi index 693fc6b90..777130ced 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_items_sync/post.pyi @@ -342,6 +342,7 @@ class SyncDataSourceItemsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.py index cf0aadb9d..12974467a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.py @@ -434,6 +434,7 @@ def get_oauth_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, @@ -602,6 +603,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.pyi index 02a57a877..862acff67 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_oauth_url/post.pyi @@ -423,6 +423,7 @@ class GetOauthUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, @@ -591,6 +592,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.py index 2ff3a0409..ee5ba6e5c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.py @@ -404,6 +404,7 @@ def sync_outlook( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, @@ -532,6 +533,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.pyi index 9e1aec668..044800b7d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_sync/post.pyi @@ -393,6 +393,7 @@ class SyncOutlookRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, @@ -521,6 +522,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.py index 32f95f5d6..887532440 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.py @@ -291,6 +291,7 @@ def list_folders( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( @@ -345,6 +346,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.pyi index a2561e2a7..865805aeb 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_outlook_user_folders/get.pyi @@ -280,6 +280,7 @@ class ListFoldersRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( @@ -334,6 +335,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.py index 06b5fcd60..4e7798645 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.py @@ -398,6 +398,7 @@ def sync_rss_feed( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.pyi index b4f222477..b09e42354 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_rss_feed/post.pyi @@ -387,6 +387,7 @@ class SyncRssFeedRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.py index 4bf037d80..fb7f392aa 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.py @@ -359,6 +359,7 @@ def create_aws_iam_user( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.pyi index 4c723594f..79afa2f0e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3/post.pyi @@ -348,6 +348,7 @@ class CreateAwsIamUserRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.py index 00593c1e8..843e0fcc8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.py @@ -407,6 +407,7 @@ def sync_s3_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, @@ -535,6 +536,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.pyi index 60e001e85..801e98297 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/integrations_s3_files/post.pyi @@ -396,6 +396,7 @@ class SyncS3FilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, @@ -524,6 +525,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.py index 29a5e6ba9..88bc495ce 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.py @@ -359,6 +359,7 @@ def toggle_user_features( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.pyi index c30af2aea..535f161d6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/modify_user_configuration/post.pyi @@ -348,6 +348,7 @@ class ToggleUserFeaturesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.py index 1be29c59e..83f948d7b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.py @@ -292,6 +292,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( @@ -346,6 +347,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.pyi index cced7688a..533208c04 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/organization/get.pyi @@ -283,6 +283,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.py index af4a2e48a..231012a2b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.py @@ -361,6 +361,7 @@ def get_parsed_file( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) @@ -429,6 +430,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.pyi index 0adabb135..fad322dbc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/parsed_file_file_id/get.pyi @@ -350,6 +350,7 @@ class GetParsedFileRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) @@ -418,6 +419,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.py index 75a641e30..74a7dcf77 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.py @@ -359,6 +359,7 @@ def process_sitemap( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) @@ -423,6 +424,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.pyi index 4abb267c7..1276ced73 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/process_sitemap/get.pyi @@ -348,6 +348,7 @@ class ProcessSitemapRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) @@ -412,6 +413,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.py index a4a0e471b..1d482b74f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.py @@ -361,6 +361,7 @@ def get_raw_file( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) @@ -429,6 +430,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.pyi index 46a8c4393..bbe9767c4 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/raw_file_file_id/get.pyi @@ -350,6 +350,7 @@ class GetRawFileRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) @@ -418,6 +419,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.py index 01d7c4d35..77e446102 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.py @@ -365,6 +365,7 @@ def resync( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, @@ -445,6 +446,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.pyi index b1036d310..671a0913e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/resync_file/post.pyi @@ -354,6 +354,7 @@ class ResyncRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, @@ -434,6 +435,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.py index 9fbca0ffa..200e42e23 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.py @@ -353,6 +353,7 @@ def revoke_access_token( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) @@ -417,6 +418,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.pyi index 17045520f..a547134ef 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/revoke_access_token/post.pyi @@ -342,6 +342,7 @@ class RevokeAccessTokenRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.py index 51f2a96cd..b0446441f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.py @@ -428,6 +428,7 @@ def scrape_sitemap( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, @@ -580,6 +581,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.pyi index 680468906..51312f0e3 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/scrape_sitemap/post.pyi @@ -417,6 +417,7 @@ class ScrapeSitemapRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, @@ -569,6 +570,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.py index 9cae2e6dc..9be54dad0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.py @@ -362,6 +362,7 @@ def search_urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) @@ -426,6 +427,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.pyi index a5d7bdded..17d04d949 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/search_urls/get.pyi @@ -351,6 +351,7 @@ class SearchUrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) @@ -415,6 +416,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.py index d3ba1bd9e..981c03b61 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.py @@ -389,6 +389,7 @@ def get_embeddings_and_chunks( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, @@ -485,6 +486,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.pyi index cc02415d1..392b6143d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/text_chunks/post.pyi @@ -378,6 +378,7 @@ class GetEmbeddingsAndChunksRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, @@ -474,6 +475,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.py index c925481db..e489185e0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.py @@ -371,6 +371,7 @@ def upload_chunks_and_embeddings( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, @@ -451,6 +452,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.pyi index f2a96c694..6ca4f9916 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_chunks_and_embeddings/post.pyi @@ -360,6 +360,7 @@ class UploadChunksAndEmbeddingsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, @@ -440,6 +441,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.py index d33b565e4..b176fc360 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.py @@ -416,6 +416,7 @@ def upload_from_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, @@ -560,6 +561,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.pyi index 63447dcae..2362aedc7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_file_from_url/post.pyi @@ -405,6 +405,7 @@ class UploadFromUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, @@ -549,6 +550,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.py index 2579dc20b..330f1d436 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.py @@ -398,6 +398,7 @@ def upload_text( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.pyi index 3df5f3864..59569ee31 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/upload_text/post.pyi @@ -387,6 +387,7 @@ class UploadTextRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.py index 8dd18d5a2..fc668dfd1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.py @@ -608,6 +608,7 @@ def upload( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, @@ -746,6 +747,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.pyi index ee1e8b24f..0319520a3 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/uploadfile/post.pyi @@ -597,6 +597,7 @@ class UploadRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, @@ -735,6 +736,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.py index e2c6918e5..e0ee2e3d3 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.py @@ -351,6 +351,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) @@ -415,6 +416,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.pyi index 681cb4c1b..c72d7177e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user/post.pyi @@ -342,6 +342,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.py index a351b150f..f0f9900e0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.py @@ -383,6 +383,7 @@ def query_user_data_sources( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, @@ -471,6 +472,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.pyi index f83936aa7..c47c170d3 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_data_sources/post.pyi @@ -372,6 +372,7 @@ class QueryUserDataSourcesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, @@ -460,6 +461,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.py index eee7b8f4e..838656397 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.py @@ -403,6 +403,7 @@ def query_user_files_deprecated( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, @@ -519,6 +520,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.pyi index aa114dd86..1c25b968a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files/post.pyi @@ -392,6 +392,7 @@ class QueryUserFilesDeprecatedRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, @@ -508,6 +509,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.py index 79f7bce93..95f7462ae 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.py @@ -401,6 +401,7 @@ def query_user_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, @@ -513,6 +514,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.pyi index 2fe4823b6..9a14d2b8a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/user_files_v2/post.pyi @@ -390,6 +390,7 @@ class QueryUserFilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, @@ -502,6 +503,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.py index 218824063..c240d52c8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.py @@ -348,6 +348,7 @@ def scrape_web( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) @@ -412,6 +413,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.pyi index 0c3a3687a..f66f992a7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/web_scrape/post.pyi @@ -337,6 +337,7 @@ class ScrapeWebRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) @@ -401,6 +402,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.py index 3f2273b51..fc2016aa7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.py @@ -381,6 +381,7 @@ def urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, @@ -469,6 +470,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.pyi index 93428441a..a39501dd9 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/paths/webhooks/post.pyi @@ -372,6 +372,7 @@ class UrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, @@ -460,6 +461,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/schemas.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/schemas.py index c1eb1c998..a2f349707 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/schemas.py @@ -975,6 +975,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1843,7 +1877,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1878,7 +1912,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1994,6 +2028,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2056,39 +2091,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/chunks_and_embeddings_upload_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/chunks_and_embeddings_upload_input.py index 54b9dba34..b0f05eac5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/chunks_and_embeddings_upload_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/chunks_and_embeddings_upload_input.py @@ -22,6 +22,7 @@ class RequiredChunksAndEmbeddingsUploadInput(TypedDict): chunks_and_embeddings: typing.List[SingleChunksAndEmbeddingsUploadInput] + class OptionalChunksAndEmbeddingsUploadInput(TypedDict, total=False): overwrite_existing: bool diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_filters.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_filters.py index 2d09407e3..2f790977d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_filters.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_filters.py @@ -19,6 +19,7 @@ class RequiredEmbeddingsAndChunksFilters(TypedDict): user_file_id: int + class OptionalEmbeddingsAndChunksFilters(TypedDict, total=False): embedding_model: typing.Optional[EmbeddingGeneratorsNullable] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_query_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_query_input.py index 196596694..b7837260e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_query_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/embeddings_and_chunks_query_input.py @@ -22,6 +22,7 @@ class RequiredEmbeddingsAndChunksQueryInput(TypedDict): filters: EmbeddingsAndChunksFilters + class OptionalEmbeddingsAndChunksQueryInput(TypedDict, total=False): pagination: Pagination diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/fresh_desk_connect_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/fresh_desk_connect_request.py index 3ebb97608..397a2bd7d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/fresh_desk_connect_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/fresh_desk_connect_request.py @@ -21,6 +21,7 @@ class RequiredFreshDeskConnectRequest(TypedDict): api_key: str + class OptionalFreshDeskConnectRequest(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/get_embedding_documents_body.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/get_embedding_documents_body.py index da727a2b5..9286d1487 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/get_embedding_documents_body.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/get_embedding_documents_body.py @@ -29,6 +29,7 @@ class RequiredGetEmbeddingDocumentsBody(TypedDict): # Number of related chunks to return. k: int + class OptionalGetEmbeddingDocumentsBody(TypedDict, total=False): tags: typing.Optional[GetEmbeddingDocumentsBodyTags] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/gmail_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/gmail_sync_input.py index 5d1d23c66..44979438b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/gmail_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/gmail_sync_input.py @@ -19,6 +19,7 @@ class RequiredGmailSyncInput(TypedDict): filters: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalGmailSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_data_source_items_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_data_source_items_request.py index 8dc016b74..759877346 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_data_source_items_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_data_source_items_request.py @@ -19,6 +19,7 @@ class RequiredListDataSourceItemsRequest(TypedDict): data_source_id: int + class OptionalListDataSourceItemsRequest(TypedDict, total=False): parent_id: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_request.py index 8715645d6..7eeff13db 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/list_request.py @@ -18,6 +18,7 @@ class RequiredListRequest(TypedDict): data_source_id: int + class OptionalListRequest(TypedDict, total=False): parent_id: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/o_auth_url_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/o_auth_url_request.py index 82b13ced3..9aacadf64 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/o_auth_url_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/o_auth_url_request.py @@ -20,6 +20,7 @@ class RequiredOAuthURLRequest(TypedDict): service: DataSourceType + class OptionalOAuthURLRequest(TypedDict, total=False): tags: typing.Union[bool, date, datetime, dict, float, int, list, str, None] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/outlook_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/outlook_sync_input.py index f9c3ce6c0..9c498c370 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/outlook_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/outlook_sync_input.py @@ -19,6 +19,7 @@ class RequiredOutlookSyncInput(TypedDict): filters: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalOutlookSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/raw_text_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/raw_text_input.py index 477993e3c..208765ba7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/raw_text_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/raw_text_input.py @@ -19,6 +19,7 @@ class RequiredRawTextInput(TypedDict): contents: str + class OptionalRawTextInput(TypedDict, total=False): name: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/resync_file_query_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/resync_file_query_input.py index f6cec1e81..d343c6672 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/resync_file_query_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/resync_file_query_input.py @@ -18,6 +18,7 @@ class RequiredResyncFileQueryInput(TypedDict): file_id: int + class OptionalResyncFileQueryInput(TypedDict, total=False): chunk_size: typing.Optional[int] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/rss_feed_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/rss_feed_input.py index 6f4459e1d..b82314f9d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/rss_feed_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/rss_feed_input.py @@ -19,6 +19,7 @@ class RequiredRSSFeedInput(TypedDict): url: str + class OptionalRSSFeedInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/s3_file_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/s3_file_sync_input.py index 309f5e04d..326e013fc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/s3_file_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/s3_file_sync_input.py @@ -20,6 +20,7 @@ class RequiredS3FileSyncInput(TypedDict): ids: typing.List[S3GetFileInput] + class OptionalS3FileSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/single_chunks_and_embeddings_upload_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/single_chunks_and_embeddings_upload_input.py index b9b527ca9..20388cc53 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/single_chunks_and_embeddings_upload_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/single_chunks_and_embeddings_upload_input.py @@ -21,6 +21,7 @@ class RequiredSingleChunksAndEmbeddingsUploadInput(TypedDict): chunks_and_embeddings: typing.List[ChunksAndEmbeddings] + class OptionalSingleChunksAndEmbeddingsUploadInput(TypedDict, total=False): chunk_size: typing.Optional[int] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sitemap_scrape_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sitemap_scrape_request.py index c04ad9606..0410ccb05 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sitemap_scrape_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sitemap_scrape_request.py @@ -22,6 +22,7 @@ class RequiredSitemapScrapeRequest(TypedDict): url: str + class OptionalSitemapScrapeRequest(TypedDict, total=False): tags: typing.Optional[SitemapScrapeRequestTags] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sync_files_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sync_files_request.py index a79a55db6..42565acca 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sync_files_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/sync_files_request.py @@ -22,6 +22,7 @@ class RequiredSyncFilesRequest(TypedDict): ids: SyncFilesRequestIds + class OptionalSyncFilesRequest(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/upload_file_from_url_input.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/upload_file_from_url_input.py index e3b523aa4..a247797ba 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/upload_file_from_url_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/upload_file_from_url_input.py @@ -19,6 +19,7 @@ class RequiredUploadFileFromUrlInput(TypedDict): url: str + class OptionalUploadFileFromUrlInput(TypedDict, total=False): file_name: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/webscrape_request.py b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/webscrape_request.py index 794562fec..bfc385925 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/webscrape_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon-urllib3-v1/python/carbon/type/webscrape_request.py @@ -22,6 +22,7 @@ class RequiredWebscrapeRequest(TypedDict): url: str + class OptionalWebscrapeRequest(TypedDict, total=False): tags: typing.Optional[WebscrapeRequestTags] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/api_client.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/api_client.py index be50c2807..1dcf12b47 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/api_client.py @@ -24,11 +24,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -52,6 +55,132 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from carbon.pydantic.add_webhook_props import AddWebhookProps +from carbon.pydantic.body_create_upload_file_uploadfile_post import BodyCreateUploadFileUploadfilePost +from carbon.pydantic.chunk_properties import ChunkProperties +from carbon.pydantic.chunk_properties_nullable import ChunkPropertiesNullable +from carbon.pydantic.chunks_and_embeddings import ChunksAndEmbeddings +from carbon.pydantic.chunks_and_embeddings_embedding import ChunksAndEmbeddingsEmbedding +from carbon.pydantic.chunks_and_embeddings_upload_input import ChunksAndEmbeddingsUploadInput +from carbon.pydantic.configuration_keys import ConfigurationKeys +from carbon.pydantic.data_source_last_sync_actions import DataSourceLastSyncActions +from carbon.pydantic.data_source_sync_statuses import DataSourceSyncStatuses +from carbon.pydantic.data_source_type import DataSourceType +from carbon.pydantic.data_source_type_nullable import DataSourceTypeNullable +from carbon.pydantic.delete_files_query_input import DeleteFilesQueryInput +from carbon.pydantic.delete_files_query_input_file_ids import DeleteFilesQueryInputFileIds +from carbon.pydantic.directory_item import DirectoryItem +from carbon.pydantic.document_response import DocumentResponse +from carbon.pydantic.document_response_list import DocumentResponseList +from carbon.pydantic.document_response_tags import DocumentResponseTags +from carbon.pydantic.document_response_vector import DocumentResponseVector +from carbon.pydantic.embedding_and_chunk import EmbeddingAndChunk +from carbon.pydantic.embedding_and_chunk_embedding import EmbeddingAndChunkEmbedding +from carbon.pydantic.embedding_generators import EmbeddingGenerators +from carbon.pydantic.embedding_generators_nullable import EmbeddingGeneratorsNullable +from carbon.pydantic.embedding_properties import EmbeddingProperties +from carbon.pydantic.embeddings_and_chunks_filters import EmbeddingsAndChunksFilters +from carbon.pydantic.embeddings_and_chunks_order_by_columns import EmbeddingsAndChunksOrderByColumns +from carbon.pydantic.embeddings_and_chunks_query_input import EmbeddingsAndChunksQueryInput +from carbon.pydantic.embeddings_and_chunks_response import EmbeddingsAndChunksResponse +from carbon.pydantic.external_file_sync_statuses import ExternalFileSyncStatuses +from carbon.pydantic.external_source_item import ExternalSourceItem +from carbon.pydantic.fetch_urls_response import FetchURLsResponse +from carbon.pydantic.fetch_urls_response_urls import FetchURLsResponseUrls +from carbon.pydantic.file_content_types import FileContentTypes +from carbon.pydantic.file_content_types_nullable import FileContentTypesNullable +from carbon.pydantic.file_formats import FileFormats +from carbon.pydantic.file_formats_nullable import FileFormatsNullable +from carbon.pydantic.file_statistics import FileStatistics +from carbon.pydantic.file_statistics_nullable import FileStatisticsNullable +from carbon.pydantic.files_query_user_files_deprecated_response import FilesQueryUserFilesDeprecatedResponse +from carbon.pydantic.fresh_desk_connect_request import FreshDeskConnectRequest +from carbon.pydantic.generic_success_response import GenericSuccessResponse +from carbon.pydantic.get_embedding_documents_body import GetEmbeddingDocumentsBody +from carbon.pydantic.get_embedding_documents_body_file_ids import GetEmbeddingDocumentsBodyFileIds +from carbon.pydantic.get_embedding_documents_body_parent_file_ids import GetEmbeddingDocumentsBodyParentFileIds +from carbon.pydantic.get_embedding_documents_body_query_vector import GetEmbeddingDocumentsBodyQueryVector +from carbon.pydantic.get_embedding_documents_body_tags import GetEmbeddingDocumentsBodyTags +from carbon.pydantic.gmail_sync_input import GmailSyncInput +from carbon.pydantic.http_validation_error import HTTPValidationError +from carbon.pydantic.hybrid_search_tuning_params import HybridSearchTuningParams +from carbon.pydantic.hybrid_search_tuning_params_nullable import HybridSearchTuningParamsNullable +from carbon.pydantic.list_data_source_items_request import ListDataSourceItemsRequest +from carbon.pydantic.list_data_source_items_response import ListDataSourceItemsResponse +from carbon.pydantic.list_request import ListRequest +from carbon.pydantic.list_response import ListResponse +from carbon.pydantic.modify_user_configuration_input import ModifyUserConfigurationInput +from carbon.pydantic.o_auth_url_request import OAuthURLRequest +from carbon.pydantic.order_dir import OrderDir +from carbon.pydantic.organization_response import OrganizationResponse +from carbon.pydantic.organization_user_data_source_api import OrganizationUserDataSourceAPI +from carbon.pydantic.organization_user_data_source_filters import OrganizationUserDataSourceFilters +from carbon.pydantic.organization_user_data_source_filters_ids import OrganizationUserDataSourceFiltersIds +from carbon.pydantic.organization_user_data_source_order_by_columns import OrganizationUserDataSourceOrderByColumns +from carbon.pydantic.organization_user_data_source_query_input import OrganizationUserDataSourceQueryInput +from carbon.pydantic.organization_user_data_source_response import OrganizationUserDataSourceResponse +from carbon.pydantic.organization_user_file_tag_create import OrganizationUserFileTagCreate +from carbon.pydantic.organization_user_file_tag_create_tags import OrganizationUserFileTagCreateTags +from carbon.pydantic.organization_user_file_tags_remove import OrganizationUserFileTagsRemove +from carbon.pydantic.organization_user_file_tags_remove_tags import OrganizationUserFileTagsRemoveTags +from carbon.pydantic.organization_user_files_to_sync_filters import OrganizationUserFilesToSyncFilters +from carbon.pydantic.organization_user_files_to_sync_filters_external_file_ids import OrganizationUserFilesToSyncFiltersExternalFileIds +from carbon.pydantic.organization_user_files_to_sync_filters_ids import OrganizationUserFilesToSyncFiltersIds +from carbon.pydantic.organization_user_files_to_sync_filters_organization_user_data_source_id import OrganizationUserFilesToSyncFiltersOrganizationUserDataSourceId +from carbon.pydantic.organization_user_files_to_sync_filters_parent_file_ids import OrganizationUserFilesToSyncFiltersParentFileIds +from carbon.pydantic.organization_user_files_to_sync_filters_tags import OrganizationUserFilesToSyncFiltersTags +from carbon.pydantic.organization_user_files_to_sync_order_by_types import OrganizationUserFilesToSyncOrderByTypes +from carbon.pydantic.organization_user_files_to_sync_query_input import OrganizationUserFilesToSyncQueryInput +from carbon.pydantic.outlook_sync_input import OutlookSyncInput +from carbon.pydantic.pagination import Pagination +from carbon.pydantic.presigned_url_response import PresignedURLResponse +from carbon.pydantic.rss_feed_input import RSSFeedInput +from carbon.pydantic.raw_text_input import RawTextInput +from carbon.pydantic.resync_file_query_input import ResyncFileQueryInput +from carbon.pydantic.revoke_access_token_input import RevokeAccessTokenInput +from carbon.pydantic.s3_auth_request import S3AuthRequest +from carbon.pydantic.s3_file_sync_input import S3FileSyncInput +from carbon.pydantic.s3_get_file_input import S3GetFileInput +from carbon.pydantic.single_chunks_and_embeddings_upload_input import SingleChunksAndEmbeddingsUploadInput +from carbon.pydantic.sitemap_scrape_request import SitemapScrapeRequest +from carbon.pydantic.sitemap_scrape_request_css_classes_to_skip import SitemapScrapeRequestCssClassesToSkip +from carbon.pydantic.sitemap_scrape_request_css_selectors_to_skip import SitemapScrapeRequestCssSelectorsToSkip +from carbon.pydantic.sitemap_scrape_request_html_tags_to_skip import SitemapScrapeRequestHtmlTagsToSkip +from carbon.pydantic.sitemap_scrape_request_tags import SitemapScrapeRequestTags +from carbon.pydantic.sync_directory_request import SyncDirectoryRequest +from carbon.pydantic.sync_files_request import SyncFilesRequest +from carbon.pydantic.sync_files_request_ids import SyncFilesRequestIds +from carbon.pydantic.text_embedding_generators import TextEmbeddingGenerators +from carbon.pydantic.token_response import TokenResponse +from carbon.pydantic.upload_file_from_url_input import UploadFileFromUrlInput +from carbon.pydantic.user_file import UserFile +from carbon.pydantic.user_file_embedding_properties import UserFileEmbeddingProperties +from carbon.pydantic.user_files_v2 import UserFilesV2 +from carbon.pydantic.user_request_content import UserRequestContent +from carbon.pydantic.user_response import UserResponse +from carbon.pydantic.user_response_unique_file_tags import UserResponseUniqueFileTags +from carbon.pydantic.utilities_scrape_web_request import UtilitiesScrapeWebRequest +from carbon.pydantic.validation_error import ValidationError +from carbon.pydantic.validation_error_loc import ValidationErrorLoc +from carbon.pydantic.webhook import Webhook +from carbon.pydantic.webhook_filters import WebhookFilters +from carbon.pydantic.webhook_filters_ids import WebhookFiltersIds +from carbon.pydantic.webhook_no_key import WebhookNoKey +from carbon.pydantic.webhook_order_by_columns import WebhookOrderByColumns +from carbon.pydantic.webhook_query_input import WebhookQueryInput +from carbon.pydantic.webhook_query_response import WebhookQueryResponse +from carbon.pydantic.webscrape_request import WebscrapeRequest +from carbon.pydantic.webscrape_request_css_classes_to_skip import WebscrapeRequestCssClassesToSkip +from carbon.pydantic.webscrape_request_css_selectors_to_skip import WebscrapeRequestCssSelectorsToSkip +from carbon.pydantic.webscrape_request_html_tags_to_skip import WebscrapeRequestHtmlTagsToSkip +from carbon.pydantic.webscrape_request_tags import WebscrapeRequestTags +from carbon.pydantic.white_labeling_response import WhiteLabelingResponse +from carbon.pydantic.youtube_transcript_response import YoutubeTranscriptResponse +from carbon.pydantic.youtube_transcript_response_raw_transcript import YoutubeTranscriptResponseRawTranscript +from carbon.pydantic.youtube_transcript_response_raw_transcript_item import YoutubeTranscriptResponseRawTranscriptItem + @dataclass class MappedArgs: body: typing.Any = None @@ -91,7 +220,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -117,6 +246,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -131,12 +263,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/configuration.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/configuration.py index e81ca743c..84710af09 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/configuration.py @@ -132,10 +132,16 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if access_token: + if type(access_token) is not str: + raise ClientConfigurationError("access_token must be a string") self.api_key['accessToken'] = access_token if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['apiKey'] = api_key if customer_id: + if type(customer_id) is not str: + raise ClientConfigurationError("customer_id must be a string") self.api_key['customerId'] = customer_id """dict to store API key(s) """ diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/exceptions.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/exceptions.py index a2106ba54..af955b055 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/exceptions.py @@ -97,48 +97,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -189,3 +147,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.py index c3ba452cb..45d124edf 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.py @@ -351,6 +351,7 @@ def add_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) @@ -415,6 +416,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.pyi index 3f66aa769..2caf7ddfc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/add_webhook/post.pyi @@ -342,6 +342,7 @@ class AddUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._add_url_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.py index a085fc4c8..86986bf38 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.py @@ -294,6 +294,7 @@ def get_access_token( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( @@ -348,6 +349,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.pyi index 76b358eab..b4d4d42ae 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_access_token/get.pyi @@ -283,6 +283,7 @@ class GetAccessTokenRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_access_token_mapped_args( ) return self._get_access_token_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.py index 8fc9f8c33..7f4b8433a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.py @@ -292,6 +292,7 @@ def get_white_labeling( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( @@ -346,6 +347,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.pyi index b7861ddac..491607325 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/auth_v1_white_labeling/get.pyi @@ -283,6 +283,7 @@ class GetWhiteLabelingRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns whether or not the organization is white labeled and which integrations are white labeled :param current_user: the current user :param db: the database session :return: a WhiteLabelingResponse """ args = self._get_white_labeling_mapped_args( ) return self._get_white_labeling_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.py index c04675dff..b3b4a0c73 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.py @@ -362,6 +362,7 @@ def create_user_file_tags( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -434,6 +435,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.pyi index 69a4322a9..f11dc5a55 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/create_user_file_tags/post.pyi @@ -351,6 +351,7 @@ class CreateUserFileTagsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -423,6 +424,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ A tag is a key-value pair that can be added to a file. This pair can then be used for searches (e.g. embedding searches) in order to narrow down the scope of the search. A file can have any number of tags. The following are reserved keys that cannot be used: - db_embedding_id - organization_id - user_id - organization_user_file_id Carbon currently supports two data types for tag values - `string` and `list`. Keys can only be `string`. If values other than `string` and `list` are used, they're automatically converted to strings (e.g. 4 will become \"4\"). """ args = self._create_user_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.py index 235abc725..a93ce587e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.py @@ -371,6 +371,7 @@ def delete_many( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, @@ -451,6 +452,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.pyi index 182f67b86..a0d4cb6bf 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_files/post.pyi @@ -360,6 +360,7 @@ class DeleteManyRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, @@ -440,6 +441,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_many_mapped_args( file_ids=file_ids, sync_statuses=sync_statuses, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.py index edce34b47..0cde98e54 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.py @@ -362,6 +362,7 @@ def delete_file_tags( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -434,6 +435,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.pyi index 346b07e75..ed024015c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_user_file_tags/post.pyi @@ -351,6 +351,7 @@ class DeleteFileTagsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, @@ -423,6 +424,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_file_tags_mapped_args( tags=tags, organization_user_file_id=organization_user_file_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.py index e9557430b..0e57727ad 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.py @@ -357,6 +357,7 @@ def delete_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) @@ -421,6 +422,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.pyi index fdca5fbb5..bf0ec9856 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/delete_webhook_webhook_id/delete.pyi @@ -348,6 +348,7 @@ class DeleteUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) @@ -412,6 +413,7 @@ class ApiFordelete(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_url_mapped_args( webhook_id=webhook_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.py index 7910ff35f..47ef692d5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.py @@ -359,6 +359,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) @@ -423,6 +424,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.pyi index 26697b2ed..194d82324 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/deletefile_file_id/delete.pyi @@ -348,6 +348,7 @@ class DeleteRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) @@ -412,6 +413,7 @@ class ApiFordelete(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._delete_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.py index cda04a502..a98428a48 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.py @@ -452,6 +452,7 @@ def get_documents( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, @@ -620,6 +621,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.pyi index 82f31cf3e..f5c39b652 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/embeddings/post.pyi @@ -441,6 +441,7 @@ class GetDocumentsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, @@ -609,6 +610,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. When querying embeddings, you can optionally specify the `media_type` parameter in your request. By default (if not set), it is equal to \"TEXT\". This means that the query will be performed over files that have been parsed as text (for now, this covers all files except image files). If it is equal to \"IMAGE\", the query will be performed over image files (for now, `.jpg` and `.png` files). You can think of this field as an additional filter on top of any filters set in `file_ids` and When `hybrid_search` is set to true, a combination of keyword search and semantic search are used to rank and select candidate embeddings during information retrieval. By default, these search methods are weighted equally during the ranking process. To adjust the weight (or \"importance\") of each search method, you can use the `hybrid_search_tuning_parameters` property. The description for the different tuning parameters are: - `weight_a`: weight to assign to semantic search - `weight_b`: weight to assign to keyword search You must ensure that `sum(weight_a, weight_b,..., weight_n)` for all *n* weights is equal to 1. The equality has an error tolerance of 0.001 to account for possible floating point issues. In order to use hybrid search for a customer across a set of documents, two flags need to be enabled: 1. Use the `/modify_user_configuration` endpoint to to enable `sparse_vectors` for the customer. The payload body for this request is below: ``` { \"configuration_key_name\": \"sparse_vectors\", \"value\": { \"enabled\": true } } ``` 2. Make sure hybrid search is enabled for the documents across which you want to perform the search. For the `/uploadfile` endpoint, this can be done by setting the following query parameter: `generate_sparse_vectors=true` Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._get_documents_mapped_args( query=query, k=k, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.py index fa43720b0..185746613 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.py @@ -362,6 +362,7 @@ def fetch_urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) @@ -426,6 +427,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.pyi index c16ed4320..7da5391d1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_urls/get.pyi @@ -351,6 +351,7 @@ class FetchUrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) @@ -415,6 +416,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a webpage. Args: url (str): URL of the webpage Returns: FetchURLsResponse: A response object with a list of URLs extracted from the webpage and the webpage content. """ args = self._fetch_urls_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.py index e1f1aeedc..9102ce93a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.py @@ -378,6 +378,7 @@ def fetch_youtube_transcripts( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, @@ -450,6 +451,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.pyi index 4dc01c1bd..1210d71a6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/fetch_youtube_transcript/get.pyi @@ -367,6 +367,7 @@ class FetchYoutubeTranscriptsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, @@ -439,6 +440,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetches english transcripts from YouTube videos. Args: id (str): The ID of the YouTube video. raw (bool): Whether to return the raw transcript or not. Defaults to False. Returns: dict: A dictionary with the transcript of the YouTube video. """ args = self._fetch_youtube_transcripts_mapped_args( id=id, raw=raw, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.py index 6188e3d6d..68be5b43a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.py @@ -257,6 +257,7 @@ def check( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( @@ -311,6 +312,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.pyi index b93a5cef8..c37513c8c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/health/get.pyi @@ -252,6 +252,7 @@ class CheckRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( @@ -306,6 +307,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.py index ce14dd256..15556cccc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.py @@ -359,6 +359,7 @@ def list_confluence_pages( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.pyi index dceff6d8c..96a5fe2cc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_list/post.pyi @@ -348,6 +348,7 @@ class ListConfluencePagesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ To begin listing a user's Confluence pages, at least a `data_source_id` of a connected Confluence account must be specified. This base request returns a list of root pages for every space the user has access to in a Confluence instance. To traverse further down the user's page directory, additional requests to this endpoint can be made with the same `data_source_id` and with `parent_id` set to the id of page from a previous request. For convenience, the `has_children` property in each directory item in the response list will flag which pages will return non-empty lists of pages when set as the `parent_id`. """ args = self._list_confluence_pages_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.py index f066d09a7..2cc9d4037 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.py @@ -413,6 +413,7 @@ def sync_confluence( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, @@ -549,6 +550,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.pyi index dae7c5783..4e8f234c7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_confluence_sync/post.pyi @@ -402,6 +402,7 @@ class SyncConfluenceRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, @@ -538,6 +539,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After listing pages in a user's Confluence account, the set of selected page `ids` and the connected account's `data_source_id` can be passed into this endpoint to sync them into Carbon. Additional parameters listed below can be used to associate data to the selected pages or alter the behavior of the sync. """ args = self._sync_confluence_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.py index 03315198a..1d254ec9f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.py @@ -413,6 +413,7 @@ def sync_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, @@ -549,6 +550,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.pyi index 0218b421a..5ac5a8d90 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_files_sync/post.pyi @@ -402,6 +402,7 @@ class SyncFilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, @@ -538,6 +539,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_files_mapped_args( data_source_id=data_source_id, ids=ids, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.py index e95129f3e..438d321a7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.py @@ -404,6 +404,7 @@ def connect_freshdesk( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, @@ -532,6 +533,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.pyi index fc60b7430..c4131669a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_freshdesk/post.pyi @@ -393,6 +393,7 @@ class ConnectFreshdeskRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, @@ -521,6 +522,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Refer this article to obtain an API key https://support.freshdesk.com/en/support/solutions/articles/215517. Make sure that your API key has the permission to read solutions from your account and you are on a paid plan. Once you have an API key, you can make a request to this endpoint along with your freshdesk domain. This will trigger an automatic sync of the articles in your \"solutions\" tab. Additional parameters below can be used to associate data with the synced articles or modify the sync behavior. """ args = self._connect_freshdesk_mapped_args( domain=domain, api_key=api_key, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.py index 5f29f72f1..462fee83a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.py @@ -398,6 +398,7 @@ def sync_gmail( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.pyi index bd24219b0..a5c539360 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_sync/post.pyi @@ -387,6 +387,7 @@ class SyncGmailRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your gmail account, you can choose which emails to sync with us using the filters parameter. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. label: Inbuilt Gmail labels, for example \"Important\" or a custom label you created. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values - starred, important, snoozed, and unread Using keys or values outside of the specified values can lead to unexpected behaviour. An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"label\", \"value\": \"Test\" } } ``` Which will list all emails that have the label \"Test\". You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"label\", \"value\": \"Personal\" }, { \"key\": \"is\", \"value\": \"starred\" } ] } ] } } ``` This will return emails after 7th of Jan that are either starred or have the label \"Personal\". Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_gmail_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.py index 1553396f3..82b93e8c6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.py @@ -291,6 +291,7 @@ def list_labels( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( @@ -345,6 +346,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.pyi index 574e8e2f2..d4808e001 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_gmail_user_labels/get.pyi @@ -280,6 +280,7 @@ class ListLabelsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( @@ -334,6 +335,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Gmail account, you can use this endpoint to list all of your labels. User created labels will have the type \"user\" and Gmail's default labels will have the type \"system\" """ args = self._list_labels_mapped_args( ) return self._list_labels_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.py index 7b86208e5..06d19008b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.py @@ -368,6 +368,7 @@ def list_data_source_items( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -448,6 +449,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.pyi index 9ada873e5..b527a3dca 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_list/post.pyi @@ -357,6 +357,7 @@ class ListDataSourceItemsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, @@ -437,6 +438,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_data_source_items_mapped_args( data_source_id=data_source_id, parent_id=parent_id, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.py index 3bc22043d..6c241127f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.py @@ -353,6 +353,7 @@ def sync_data_source_items( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) @@ -417,6 +418,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.pyi index 693fc6b90..777130ced 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_items_sync/post.pyi @@ -342,6 +342,7 @@ class SyncDataSourceItemsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_data_source_items_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.py index cf0aadb9d..12974467a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.py @@ -434,6 +434,7 @@ def get_oauth_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, @@ -602,6 +603,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.pyi index 02a57a877..862acff67 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_oauth_url/post.pyi @@ -423,6 +423,7 @@ class GetOauthUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, @@ -591,6 +592,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_oauth_url_mapped_args( service=service, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.py index 2ff3a0409..ee5ba6e5c 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.py @@ -404,6 +404,7 @@ def sync_outlook( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, @@ -532,6 +533,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.pyi index 9e1aec668..044800b7d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_sync/post.pyi @@ -393,6 +393,7 @@ class SyncOutlookRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, @@ -521,6 +522,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Once you have successfully connected your Outlook account, you can choose which emails to sync with us using the filters and folder parameter. \"folder\" should be the folder you want to sync from Outlook. By default we get messages from your inbox folder. Filters is a JSON object with key value pairs. It also supports AND and OR operations. For now, we support a limited set of keys listed below. category: Custom categories that you created in Outlook. after or before: A date in YYYY/mm/dd format (example 2023/12/31). Gets emails after/before a certain date. You can also use them in combination to get emails from a certain period. is: Can have the following values: flagged An example of a basic query with filters can be ```json { \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` Which will list all emails that have the category \"Test\". Specifying a custom folder in the same query ```json { \"folder\": \"Folder Name\", \"filters\": { \"key\": \"category\", \"value\": \"Test\" } } ``` You can use AND and OR operation in the following way: ```json { \"filters\": { \"AND\": [ { \"key\": \"after\", \"value\": \"2024/01/07\" }, { \"OR\": [ { \"key\": \"category\", \"value\": \"Personal\" }, { \"key\": \"category\", \"value\": \"Test\" }, ] } ] } } ``` This will return emails after 7th of Jan that have either Personal or Test as category. Note that this is the highest level of nesting we support, i.e. you can't add more AND/OR filters within the OR filter in the above example. """ args = self._sync_outlook_mapped_args( filters=filters, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.py index 32f95f5d6..887532440 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.py @@ -291,6 +291,7 @@ def list_folders( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( @@ -345,6 +346,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.pyi index a2561e2a7..865805aeb 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_outlook_user_folders/get.pyi @@ -280,6 +280,7 @@ class ListFoldersRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( @@ -334,6 +335,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After connecting your Outlook account, you can use this endpoint to list all of your folders on outlook. This includes both system folders like \"inbox\" and user created folders. """ args = self._list_folders_mapped_args( ) return self._list_folders_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.py index 06b5fcd60..4e7798645 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.py @@ -398,6 +398,7 @@ def sync_rss_feed( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.pyi index b4f222477..b09e42354 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_rss_feed/post.pyi @@ -387,6 +387,7 @@ class SyncRssFeedRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._sync_rss_feed_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.py index 4bf037d80..fb7f392aa 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.py @@ -359,6 +359,7 @@ def create_aws_iam_user( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.pyi index 4c723594f..79afa2f0e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3/post.pyi @@ -348,6 +348,7 @@ class CreateAwsIamUserRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Create a new IAM user with permissions to:
  1. List all buckets.
  2. Read from the specific buckets and objects to sync with Carbon. Ensure any future buckets or objects carry the same permissions.
Once created, generate an access key for this user and share the credentials with us. We recommend testing this key beforehand. """ args = self._create_aws_iam_user_mapped_args( access_key=access_key, access_key_secret=access_key_secret, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.py index 00593c1e8..843e0fcc8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.py @@ -407,6 +407,7 @@ def sync_s3_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, @@ -535,6 +536,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.pyi index 60e001e85..801e98297 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/integrations_s3_files/post.pyi @@ -396,6 +396,7 @@ class SyncS3FilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, @@ -524,6 +525,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ After optionally loading the items via /integrations/items/sync and integrations/items/list, use the bucket name and object key as the ID in this endpoint to sync them into Carbon. Additional parameters below can associate data with the selected items or modify the sync behavior """ args = self._sync_s3_files_mapped_args( ids=ids, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.py index 29a5e6ba9..88bc495ce 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.py @@ -359,6 +359,7 @@ def toggle_user_features( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, @@ -431,6 +432,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.pyi index c30af2aea..535f161d6 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/modify_user_configuration/post.pyi @@ -348,6 +348,7 @@ class ToggleUserFeaturesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, @@ -420,6 +421,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._toggle_user_features_mapped_args( configuration_key_name=configuration_key_name, value=value, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.py index 1be29c59e..83f948d7b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.py @@ -292,6 +292,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( @@ -346,6 +347,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.pyi index cced7688a..533208c04 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/organization/get.pyi @@ -283,6 +283,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( @@ -337,6 +338,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.py index af4a2e48a..231012a2b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.py @@ -361,6 +361,7 @@ def get_parsed_file( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) @@ -429,6 +430,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.pyi index 0adabb135..fad322dbc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/parsed_file_file_id/get.pyi @@ -350,6 +350,7 @@ class GetParsedFileRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) @@ -418,6 +419,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_parsed_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.py index 75a641e30..74a7dcf77 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.py @@ -359,6 +359,7 @@ def process_sitemap( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) @@ -423,6 +424,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.pyi index 4abb267c7..1276ced73 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/process_sitemap/get.pyi @@ -348,6 +348,7 @@ class ProcessSitemapRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) @@ -412,6 +413,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Retrieves all URLs from a sitemap, which can subsequently be utilized with our `web_scrape` endpoint. """ args = self._process_sitemap_mapped_args( url=url, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.py index a4a0e471b..1d482b74f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.py @@ -361,6 +361,7 @@ def get_raw_file( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) @@ -429,6 +430,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.pyi index 46a8c4393..bbe9767c4 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/raw_file_file_id/get.pyi @@ -350,6 +350,7 @@ class GetRawFileRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) @@ -418,6 +419,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._get_raw_file_mapped_args( file_id=file_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.py index 01d7c4d35..77e446102 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.py @@ -365,6 +365,7 @@ def resync( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, @@ -445,6 +446,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.pyi index b1036d310..671a0913e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/resync_file/post.pyi @@ -354,6 +354,7 @@ class ResyncRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, @@ -434,6 +435,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._resync_mapped_args( file_id=file_id, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.py index 9fbca0ffa..200e42e23 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.py @@ -353,6 +353,7 @@ def revoke_access_token( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) @@ -417,6 +418,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.pyi index 17045520f..a547134ef 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/revoke_access_token/post.pyi @@ -342,6 +342,7 @@ class RevokeAccessTokenRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._revoke_access_token_mapped_args( data_source_id=data_source_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.py index 51f2a96cd..b0446441f 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.py @@ -428,6 +428,7 @@ def scrape_sitemap( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, @@ -580,6 +581,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.pyi index 680468906..51312f0e3 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/scrape_sitemap/post.pyi @@ -417,6 +417,7 @@ class ScrapeSitemapRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, @@ -569,6 +570,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Extracts all URLs from a sitemap and performs a web scrape on each of them. Args: sitemap_url (str): URL of the sitemap Returns: dict: A response object with the status of the scraping job message.--> """ args = self._scrape_sitemap_mapped_args( url=url, tags=tags, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.py index 9cae2e6dc..9be54dad0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.py @@ -362,6 +362,7 @@ def search_urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) @@ -426,6 +427,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.pyi index a5d7bdded..17d04d949 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/search_urls/get.pyi @@ -351,6 +351,7 @@ class SearchUrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) @@ -415,6 +416,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Perform a web search and obtain a list of relevant URLs. As an illustration, when you perform a search for “content related to MRNA,” you will receive a list of links such as the following: - https://tomrenz.substack.com/p/mrna-and-why-it-matters - https://www.statnews.com/2020/11/10/the-story-of-mrna-how-a-once-dismissed-idea-became-a-leading-technology-in-the-covid-vaccine-race/ - https://www.statnews.com/2022/11/16/covid-19-vaccines-were-a-success-but-mrna-still-has-a-delivery-problem/ - https://joomi.substack.com/p/were-still-being-misled-about-how Subsequently, you can submit these links to the web_scrape endpoint in order to retrieve the content of the respective web pages. Args: query (str): Query to search for Returns: FetchURLsResponse: A response object with a list of URLs for a given search query. """ args = self._search_urls_mapped_args( query=query, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.py index d3ba1bd9e..981c03b61 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.py @@ -389,6 +389,7 @@ def get_embeddings_and_chunks( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, @@ -485,6 +486,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.pyi index cc02415d1..392b6143d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/text_chunks/post.pyi @@ -378,6 +378,7 @@ class GetEmbeddingsAndChunksRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, @@ -474,6 +475,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_embeddings_and_chunks_mapped_args( filters=filters, pagination=pagination, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.py index c925481db..e489185e0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.py @@ -371,6 +371,7 @@ def upload_chunks_and_embeddings( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, @@ -451,6 +452,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.pyi index f2a96c694..6ca4f9916 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_chunks_and_embeddings/post.pyi @@ -360,6 +360,7 @@ class UploadChunksAndEmbeddingsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, @@ -440,6 +441,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_chunks_and_embeddings_mapped_args( embedding_model=embedding_model, chunks_and_embeddings=chunks_and_embeddings, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.py index d33b565e4..b176fc360 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.py @@ -416,6 +416,7 @@ def upload_from_url( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, @@ -560,6 +561,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.pyi index 63447dcae..2362aedc7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_file_from_url/post.pyi @@ -405,6 +405,7 @@ class UploadFromUrlRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, @@ -549,6 +550,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._upload_from_url_mapped_args( url=url, file_name=file_name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.py index 2579dc20b..330f1d436 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.py @@ -398,6 +398,7 @@ def upload_text( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, @@ -518,6 +519,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.pyi index 3df5f3864..59569ee31 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/upload_text/post.pyi @@ -387,6 +387,7 @@ class UploadTextRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, @@ -507,6 +508,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_text_mapped_args( contents=contents, name=name, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.py index 8dd18d5a2..fc668dfd1 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.py @@ -608,6 +608,7 @@ def upload( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, @@ -746,6 +747,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.pyi index ee1e8b24f..0319520a3 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/uploadfile/post.pyi @@ -597,6 +597,7 @@ class UploadRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, @@ -735,6 +736,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint is used to directly upload local files to Carbon. The `POST` request should be a multipart form request. Note that the `set_page_as_boundary` query parameter is applicable only to PDFs for now. When this value is set, PDF chunks are at most one page long. Additional information can be retrieved for each chunk, however, namely the coordinates of the bounding box around the chunk (this can be used for things like text highlighting). Following is a description of all possible query parameters: - `chunk_size`: the chunk size (in tokens) applied when splitting the document - `chunk_overlap`: the chunk overlap (in tokens) applied when splitting the document - `skip_embedding_generation`: whether or not to skip the generation of chunks and embeddings - `set_page_as_boundary`: described above - `embedding_model`: the model used to generate embeddings for the document chunks - `use_ocr`: whether or not to use OCR as a preprocessing step prior to generating chunks (only valid for PDFs currently) - `generate_sparse_vectors`: whether or not to generate sparse vectors for the file. Required for hybrid search. - `prepend_filename_to_chunks`: whether or not to prepend the filename to the chunk text Carbon supports multiple models for use in generating embeddings for files. For images, we support Vertex AI's multimodal model; for text, we support OpenAI's `text-embedding-ada-002` and Cohere's embed-multilingual-v3.0. The model can be specified via the `embedding_model` parameter (in the POST body for `/embeddings`, and a query parameter in `/uploadfile`). If no model is supplied, the `text-embedding-ada-002` is used by default. When performing embedding queries, embeddings from files that used the specified model will be considered in the query. For example, if files A and B have embeddings generated with `OPENAI`, and files C and D have embeddings generated with `COHERE_MULTILINGUAL_V3`, then by default, queries will only consider files A and B. If `COHERE_MULTILINGUAL_V3` is specified as the `embedding_model` in `/embeddings`, then only files C and D will be considered. Make sure that the set of all files you want considered for a query have embeddings generated via the same model. For now, **do not** set `VERTEX_MULTIMODAL` as an `embedding_model`. This model is used automatically by Carbon when it detects an image file. """ args = self._upload_mapped_args( file=file, chunk_size=chunk_size, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.py index e2c6918e5..e0ee2e3d3 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.py @@ -351,6 +351,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) @@ -415,6 +416,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.pyi index 681cb4c1b..c72d7177e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user/post.pyi @@ -342,6 +342,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) @@ -406,6 +407,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( customer_id=customer_id, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.py index a351b150f..f0f9900e0 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.py @@ -383,6 +383,7 @@ def query_user_data_sources( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, @@ -471,6 +472,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.pyi index f83936aa7..c47c170d3 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_data_sources/post.pyi @@ -372,6 +372,7 @@ class QueryUserDataSourcesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, @@ -460,6 +461,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._query_user_data_sources_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.py index eee7b8f4e..838656397 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.py @@ -403,6 +403,7 @@ def query_user_files_deprecated( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, @@ -519,6 +520,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.pyi index aa114dd86..1c25b968a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files/post.pyi @@ -392,6 +392,7 @@ class QueryUserFilesDeprecatedRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, @@ -508,6 +509,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This route is deprecated. Use `/user_files_v2` instead. """ args = self._query_user_files_deprecated_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.py index 79f7bce93..95f7462ae 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.py @@ -401,6 +401,7 @@ def query_user_files( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, @@ -513,6 +514,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.pyi index 2fe4823b6..9a14d2b8a 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/user_files_v2/post.pyi @@ -390,6 +390,7 @@ class QueryUserFilesRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, @@ -502,6 +503,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ For pre-filtering documents, using `tags_v2` is preferred to using `tags` (which is now deprecated). If both `tags_v2` and `tags` are specified, `tags` is ignored. `tags_v2` enables building complex filters through the use of \"AND\", \"OR\", and negation logic. Take the below input as an example: ```json { \"OR\": [ { \"key\": \"subject\", \"value\": \"holy-bible\", \"negate\": false }, { \"key\": \"person-of-interest\", \"value\": \"jesus christ\", \"negate\": false }, { \"key\": \"genre\", \"value\": \"religion\", \"negate\": true } { \"AND\": [ { \"key\": \"subject\", \"value\": \"tao-te-ching\", \"negate\": false }, { \"key\": \"author\", \"value\": \"lao-tzu\", \"negate\": false } ] } ] } ``` In this case, files will be filtered such that: 1. \"subject\" = \"holy-bible\" OR 2. \"person-of-interest\" = \"jesus christ\" OR 3. \"genre\" != \"religion\" OR 4. \"subject\" = \"tao-te-ching\" AND \"author\" = \"lao-tzu\" Note that the top level of the query must be either an \"OR\" or \"AND\" array. Currently, nesting is limited to 3. For tag blocks (those with \"key\", \"value\", and \"negate\" keys), the following typing rules apply: 1. \"key\" isn't optional and must be a `string` 2. \"value\" isn't optional and can be `any` or list[`any`] 3. \"negate\" is optional and must be `true` or `false`. If present and `true`, then the filter block is negated in the resulting query. It is `false` by default. """ args = self._query_user_files_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.py index 218824063..c240d52c8 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.py @@ -348,6 +348,7 @@ def scrape_web( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) @@ -412,6 +413,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.pyi index 0c3a3687a..f66f992a7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/web_scrape/post.pyi @@ -337,6 +337,7 @@ class ScrapeWebRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) @@ -401,6 +402,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Conduct a web scrape on a given webpage URL. Our web scraper is fully compatible with JavaScript and supports recursion depth, enabling you to efficiently extract all content from the target website. """ args = self._scrape_web_mapped_args( body=body, ) diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.py index 3f2273b51..fc2016aa7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.py @@ -381,6 +381,7 @@ def urls( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, @@ -469,6 +470,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.pyi b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.pyi index 93428441a..a39501dd9 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/paths/webhooks/post.pyi @@ -372,6 +372,7 @@ class UrlsRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, @@ -460,6 +461,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._urls_mapped_args( pagination=pagination, order_by=order_by, diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/schemas.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/schemas.py index c1eb1c998..a2f349707 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/schemas.py @@ -975,6 +975,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1843,7 +1877,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1878,7 +1912,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1994,6 +2028,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2056,39 +2091,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/chunks_and_embeddings_upload_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/chunks_and_embeddings_upload_input.py index 54b9dba34..b0f05eac5 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/chunks_and_embeddings_upload_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/chunks_and_embeddings_upload_input.py @@ -22,6 +22,7 @@ class RequiredChunksAndEmbeddingsUploadInput(TypedDict): chunks_and_embeddings: typing.List[SingleChunksAndEmbeddingsUploadInput] + class OptionalChunksAndEmbeddingsUploadInput(TypedDict, total=False): overwrite_existing: bool diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_filters.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_filters.py index 2d09407e3..2f790977d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_filters.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_filters.py @@ -19,6 +19,7 @@ class RequiredEmbeddingsAndChunksFilters(TypedDict): user_file_id: int + class OptionalEmbeddingsAndChunksFilters(TypedDict, total=False): embedding_model: typing.Optional[EmbeddingGeneratorsNullable] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_query_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_query_input.py index 196596694..b7837260e 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_query_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/embeddings_and_chunks_query_input.py @@ -22,6 +22,7 @@ class RequiredEmbeddingsAndChunksQueryInput(TypedDict): filters: EmbeddingsAndChunksFilters + class OptionalEmbeddingsAndChunksQueryInput(TypedDict, total=False): pagination: Pagination diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/fresh_desk_connect_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/fresh_desk_connect_request.py index 3ebb97608..397a2bd7d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/fresh_desk_connect_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/fresh_desk_connect_request.py @@ -21,6 +21,7 @@ class RequiredFreshDeskConnectRequest(TypedDict): api_key: str + class OptionalFreshDeskConnectRequest(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/get_embedding_documents_body.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/get_embedding_documents_body.py index da727a2b5..9286d1487 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/get_embedding_documents_body.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/get_embedding_documents_body.py @@ -29,6 +29,7 @@ class RequiredGetEmbeddingDocumentsBody(TypedDict): # Number of related chunks to return. k: int + class OptionalGetEmbeddingDocumentsBody(TypedDict, total=False): tags: typing.Optional[GetEmbeddingDocumentsBodyTags] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/gmail_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/gmail_sync_input.py index 5d1d23c66..44979438b 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/gmail_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/gmail_sync_input.py @@ -19,6 +19,7 @@ class RequiredGmailSyncInput(TypedDict): filters: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalGmailSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_data_source_items_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_data_source_items_request.py index 8dc016b74..759877346 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_data_source_items_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_data_source_items_request.py @@ -19,6 +19,7 @@ class RequiredListDataSourceItemsRequest(TypedDict): data_source_id: int + class OptionalListDataSourceItemsRequest(TypedDict, total=False): parent_id: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_request.py index 8715645d6..7eeff13db 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/list_request.py @@ -18,6 +18,7 @@ class RequiredListRequest(TypedDict): data_source_id: int + class OptionalListRequest(TypedDict, total=False): parent_id: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/o_auth_url_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/o_auth_url_request.py index 82b13ced3..9aacadf64 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/o_auth_url_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/o_auth_url_request.py @@ -20,6 +20,7 @@ class RequiredOAuthURLRequest(TypedDict): service: DataSourceType + class OptionalOAuthURLRequest(TypedDict, total=False): tags: typing.Union[bool, date, datetime, dict, float, int, list, str, None] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/outlook_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/outlook_sync_input.py index f9c3ce6c0..9c498c370 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/outlook_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/outlook_sync_input.py @@ -19,6 +19,7 @@ class RequiredOutlookSyncInput(TypedDict): filters: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalOutlookSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/raw_text_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/raw_text_input.py index 477993e3c..208765ba7 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/raw_text_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/raw_text_input.py @@ -19,6 +19,7 @@ class RequiredRawTextInput(TypedDict): contents: str + class OptionalRawTextInput(TypedDict, total=False): name: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/resync_file_query_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/resync_file_query_input.py index f6cec1e81..d343c6672 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/resync_file_query_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/resync_file_query_input.py @@ -18,6 +18,7 @@ class RequiredResyncFileQueryInput(TypedDict): file_id: int + class OptionalResyncFileQueryInput(TypedDict, total=False): chunk_size: typing.Optional[int] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/rss_feed_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/rss_feed_input.py index 6f4459e1d..b82314f9d 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/rss_feed_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/rss_feed_input.py @@ -19,6 +19,7 @@ class RequiredRSSFeedInput(TypedDict): url: str + class OptionalRSSFeedInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/s3_file_sync_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/s3_file_sync_input.py index 309f5e04d..326e013fc 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/s3_file_sync_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/s3_file_sync_input.py @@ -20,6 +20,7 @@ class RequiredS3FileSyncInput(TypedDict): ids: typing.List[S3GetFileInput] + class OptionalS3FileSyncInput(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/single_chunks_and_embeddings_upload_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/single_chunks_and_embeddings_upload_input.py index b9b527ca9..20388cc53 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/single_chunks_and_embeddings_upload_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/single_chunks_and_embeddings_upload_input.py @@ -21,6 +21,7 @@ class RequiredSingleChunksAndEmbeddingsUploadInput(TypedDict): chunks_and_embeddings: typing.List[ChunksAndEmbeddings] + class OptionalSingleChunksAndEmbeddingsUploadInput(TypedDict, total=False): chunk_size: typing.Optional[int] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sitemap_scrape_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sitemap_scrape_request.py index c04ad9606..0410ccb05 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sitemap_scrape_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sitemap_scrape_request.py @@ -22,6 +22,7 @@ class RequiredSitemapScrapeRequest(TypedDict): url: str + class OptionalSitemapScrapeRequest(TypedDict, total=False): tags: typing.Optional[SitemapScrapeRequestTags] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sync_files_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sync_files_request.py index a79a55db6..42565acca 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sync_files_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/sync_files_request.py @@ -22,6 +22,7 @@ class RequiredSyncFilesRequest(TypedDict): ids: SyncFilesRequestIds + class OptionalSyncFilesRequest(TypedDict, total=False): tags: typing.Optional[typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]]] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/upload_file_from_url_input.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/upload_file_from_url_input.py index e3b523aa4..a247797ba 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/upload_file_from_url_input.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/upload_file_from_url_input.py @@ -19,6 +19,7 @@ class RequiredUploadFileFromUrlInput(TypedDict): url: str + class OptionalUploadFileFromUrlInput(TypedDict, total=False): file_name: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/webscrape_request.py b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/webscrape_request.py index 794562fec..bfc385925 100644 --- a/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/webscrape_request.py +++ b/generator/konfig-integration-tests/sdks/python-carbon/python/carbon/type/webscrape_request.py @@ -22,6 +22,7 @@ class RequiredWebscrapeRequest(TypedDict): url: str + class OptionalWebscrapeRequest(TypedDict, total=False): tags: typing.Optional[WebscrapeRequestTags] diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/api_client.py b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/api_client.py index 6c773b397..a21e7334b 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_circular_reference_2.pydantic.has_optional_var import HasOptionalVar +from python_circular_reference_2.pydantic.has_required_var import HasRequiredVar + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/configuration.py b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/configuration.py index 5082d7f42..40a50e0e0 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/exceptions.py b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/exceptions.py index 6c3056662..630758456 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.py index 4994f9dce..d914e8ae7 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.pyi index 11605b181..9bd658856 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/schemas.py b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/schemas.py index f11c37183..609402538 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference-2/python/python_circular_reference_2/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/api_client.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/api_client.py index e0c4d3109..ff3475cbe 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,12 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_circular_reference.pydantic.item import Item +from python_circular_reference.pydantic.test_fetch_response import TestFetchResponse +from python_circular_reference.pydantic.test_infinite_loop import TestInfiniteLoop + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +101,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +127,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +144,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/configuration.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/configuration.py index f9d60f279..c0da1d1d3 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/exceptions.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/exceptions.py index 36c0fba33..75e31f390 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.py index dd8b951ea..0303fec92 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.pyi index 4e300f7bb..2c83362f3 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/schemas.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/schemas.py index 41987134c..4b3c492e8 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_fetch_response.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_fetch_response.py index a7a187499..ab9050d4b 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_fetch_response.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_fetch_response.py @@ -22,6 +22,7 @@ class RequiredTestFetchResponse(TypedDict): required: 'TestInfiniteLoop' + class OptionalTestFetchResponse(TypedDict, total=False): value: 'TestInfiniteLoop' diff --git a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_infinite_loop.py b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_infinite_loop.py index 9e38eab9b..f59f4a174 100644 --- a/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_infinite_loop.py +++ b/generator/konfig-integration-tests/sdks/python-circular-reference/python/python_circular_reference/type/test_infinite_loop.py @@ -21,6 +21,7 @@ class RequiredTestInfiniteLoop(TypedDict): required: 'TestFetchResponse' + class OptionalTestInfiniteLoop(TypedDict, total=False): value: 'TestFetchResponse' diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/.coverage b/generator/konfig-integration-tests/sdks/python-decentro/python/.coverage index 37b754c458cce4f50da526d8970a5313071733af..5fa5e7fc9af73be11597824670a423cde654538a 100644 GIT binary patch literal 94208 zcmeI53v?S-na8iBv7{M|X8e{NC$SR0rd)KYs*6xkRd20nPyc!$5>%5Wh zY44yK@g5KMtKML!Cm2wo!BDR^+NT;@4{2%-uIL~Rsye)36WJe!{J|dBE2{RwAqFGC z0VOi*J)sUakPQ;Q7FBPJ#v|Y$YOptixA4{`cCYhB)Z=PI4Fyy!PEi}|sT1mMJ100i z1qGIOtK^)NNC5u3rko8#Bu}N|I22dSD8G+Ko~f0jmFP55+3kH z!`}X2h@56f3r2(CkXOA`4Gcxqo*7TD0gGn5K)lqmfn#;y6Y7fZnfR>~b&@;JuxDcP z#LmY7E)+IoP40+)8g?ekp`n3pko=aRfkB)&ut)rdqv1?@X4*FzPMqwl(`JUWOrGzQ z8)mycb{m|a>D?`yR z`Rs?p_b-Mw@%B8Y!&6>vdG|?@QLsGz?qF1#4DeGj&17_jtb@PLoNsU`nVLy(DeCX{ zhL4jXgZK8v69;m0YMJpFVki+@(7fTqhCoU+w_#Xd@OJlyyQk(gl4CR#3JCZDW3%H! zp#Ux_8a{_W_>>w^dex@Hw{f>XJ0n5XSuo}SCvq_Zh$>H zH2BS+<|Pc%Yo)cxV`#(p7`>-z2$NB{U^l-P3Y}5DATThXgnAP76|RQkM+M)H3n%`a zxD$aLy){rMH7KHK$21O__!fICU3pb0+efYK8$?l@6Wj(ECHop!i*ZM0E|s?p$p z>cyK77?QD0E1EYDQQ=FdOY3TE*|GsnE&pQtj(f>Y+?3PHEe=n8y+t2N6vnup@oP}2 z4=4t9;-hs+CQ17;nO}B-!-dvPYCgf*rO1Il#(x1jw|EM6$5k-4O0;!^IyX>S08@Y|z!YE#{Ou`Vvsf(--2b=AKS%Nfcw;Z708@Y| zz!YE#Fa?+bOaZ0#Xp+u#bO~uXPSPo^mX-pUnAcj*B~J`?U2n>o&_Mx`5h^ zBZJjzN;wqU5sKQI=zwisAD&CE(f#;6TNfO^!lsOj0Zxe#zwGvM~BQ9oP|9nut10{vQ4i4JMW ze5*zx;RsgPR{+R?>jBv)YK!uL_~3OwjOAUC2e2p20ZTl)>K{~w2f!Ko;bPPi$qa$j z^$%);{-H<^gE!>@xG6kvqDsmJj)CiB05*jO&JK)OYb9Vcg$K^Wn)JYKKsAL2o)IbcRV2{a{UdzSySpNEFr2VD+ z|5Dw@#S{~fUaS9KqA%iN`>z9F$k-mej*E4gn$>817VC{%?5KHB(^{WJ`eH7ongVyW z{r^I}nTrLk3*^#4V@n2Y&nQqA1|cj*Eb^U&l<_WuQa z4i{^o$&$JM&+A28tkDc?Q~Li-J(r7B(8LNr*CO9MjyHW)aatuY7kFj8nv3nEsT#gp zq2@ca#2AU!$V4a}j`yWFjk@7Q!+U|Zm^yECcu+MahBJ)9L#4J1SRXWZ+YAULeHj-c zwtm`@B#KsIY3)y zj)m7zr*r(mxuMrSu>WrDY~-o$zwl=vwv(uo^DEc}(Y4!f^vcqS2L=v5^Kkpb`mOj>xUK1@VrhHKVZdYi$8zJ7 z_l%4#JJ72xblKK+c|Q81Y`+N(EZsCJbbu}Hh^N689Nq#+^C7pe8HYFHc)PF(hc}V4 zENF*tZ9Czd_{qbK{Q&PM+6a*i8`I(EZh+|38*p^V-6y|Y+WX|n7uG)aFq|+XQhEM* z__lgI*~v)d_I3Eogmvj>=0Hzhuox$U?Ul(B-EvMw=g*S(bE(5HaN7@ zHp;IBTeucZVh+Cs2iHLG7U4z+7T@R`ANcGo@(mF7-asIF4?k0UC9f4CDqBfJB56FU zA*y*biTdc3pOC!QK4BZNw620LZe4|8J6$il*!`&Y#dj3HH1g;q8zvn+hu_KT{u|L5 z^pf>y+m^SZ%l4J9v$S$lXaQT?f<^zaumXoy#1msV4ll=|FBg{K@UnP#DGo0s+t`;t zSXyGuUktW-@f0bGn<1{LnZ$i%Ehyd(CFUH;E%xDfABlf9B|g6iAERl?F}#fsx4sd_ zkpx`&)XEno{xA?fSmWi13EAENTSyI7z8-90y>tAkr(+RL!~8|*X*esDVIn4R`Sm zTOIal{AG2YqY8gn<+a%>aYUunSphb`!dhFvFN9FxLhkAFIl=-67BAo~-t{OXIF9x@ z$G`NFP>!R^o#Q7u9sGP8Js+Z1^Yd_U9^QhVi-U7IP4)?3&l8GjN>J~2yb3Q_AJD~LI_HH0S*>GaJ7(+H_msCKl|WnJ`YFd z;f;k{9G#1gH&2jpSdND!9F|~{2Vdgdcyl-2+%7^;60Ncetk?AqzqX;V`}Utc?TEDq zkU+PG1n2lf@#}MzZ$Npg@3f-aw)YkE+F!Zv@_mn3cFaMj3w7B?EEh(l;|RShUVQPV z!z1@!ned>I(;l?x>e@3Sa20iGYU1$7#Ke_}iHQsFH}M<^3`ip-s27R3V`#b8xA=?-dQFB-G zsJ(eK=WW8o8?XQ20puJRgMG$+`lpE;w;hf-*A6HBm3wy z-*AiiSu3#K_6{p|5enHkG!E(IeyIA=E0zED!Gg};E&leO{cqpwUNiBFFL6)7(QiA` zH8BPUdIpq#MkYTu{<=)zx$`J9JY0hVP`J4S&fVjVjxqP8=?UBs7k z9l87%`2vnQ@%>AIiIS_Y+!c=+xmu0@ogXC|ocB9*;6u9QUw(s7=?StE{Q6kwmw)`< zXd^;#Z)|alqf=c@3&%srAE|r{&;K8D4{jcta-CuBj#{Eh6N8BHD-|2p*`>gvk zz_S-qfGNNfUdLx zuO?>IDq>cyB&MZ>m=!CCS-zZ@Wy^?Jx|EnDONd##n3(2fVthVgnwp4dY$T?kftdPw zViqkTrml{d+FD|2YKW<>CZ?*2n953GDk_LsxR96y3yAT0i7789X8wF)=FKB!?p$KZ z%7~dWhnUh*VoFMg@py08@Y|z!YE#Fa_SU0(kzP_5a_rd~8Ri08@Y|z!YE#Fa?+bOaZ0_>8*$Z6#s;0kSh)-kK+P5ykP|-^(yX*YgF$$z>G7dZ5774N zHC${rO-*O>5K92{QGbSMc2MJK*NxPlWt)XF?NQfFdL9?6qM!IFkF0Ib^SM|JO(gZ! zfI5iFvgYqrG!?R*U3YV_dFEgO9FG1oo5P{w!QP>Wl5lwr`b7OfH5By+hO}sS05n>t z^IWWmW|9R65uhy4ycQ~ogj@UU!sBwM-mZ@!BAA~jW?|tqpB9wd|J;5=yeW9`@*5d z9yI_Bok%$G*=KzA2SfhU+C9$TOGzxe{@;V1MDk72sQVT7I`KoU-?}ymALcLc+nk?q zOgK92U$8rKj-V&GF|N^eoAqbbxt1>U(|9LdpToskXr^>{5Vr%MS?(WHBGl_N(#O(L zc{QFJ|)!CuTIvE zerVGwzpYb8+ zY58*p^*&cz(u|;xIk)QzxL7;=GBg9Dku$fMq?o58re({WdIJ~3lO@zz$f>EFs0<-b z5*erE&3022qD-`qK{rw#V9744kxMt2q~eU{(lkNSvg&%hiHrH^XH{sjPZ>{%52hsZ zsv3!eBajDf&>OkfQStekAzZA72S(APt9d_ujaV8 zgSJmwU$btrjG_y$OY)`HlyWGxhoZlRQCTGv4F-JIs9E%;5+GH~Lz?DYrY005kY48j z;Qi(Y#;mo)z}jhMR-=m18;St+sA*BtY8kz`5O7s9;9kQM`i+W4_Z0wg;Cet#)HV8| zd>}q}9T4NPwjvK;PnrYvFR5|#rd$9wg$Fifk+W2l!~@F!YzhyY9hi7v30O_xfitlt zJ+K>4P2quOL{0a=1tQ?qo1wg=41elHE}-&Jq)H6f;Taeh`&0~9$_v2dp~$5L`qTjh z&nD}oJg~G-WHAN~y4B<12n=&Y`u%<3FrKE@3!T8$XaY9nI3Bn*uw(~dRZzqVq^%{> z;kM`~Rzs0!`T{^*$^oVY6q)d}a>_inE^+`gk0MY~B%HbJHo(cFhy&W-88%(CQr2b4 z{J$<(0H>6qE-5ugy#K!r$%mvbNe=fR@t;M9>wxe*p_Ts}U*^2s@his~`)BR896$Fs zx6F2@b==xwxdZ(OtxI(Ob$JP#4NYGW9UfFu=iK$Bi-G6_MSbJLoHI5nCd(_Cc}p3I z(d(Om`tbEYjf+&Z4`_FroEC%DH32Bi)_a!Bklx0uY6RAurWJLv>7LsFoK@60Q{0$d zR1Zir8^URgJfkJGU=eU_rYP0)B`C%+QDXs$UR6gq+ht))P2=2J%Gqw(@)NzPhO%^I z@#T!G_>JlZuaVcws)4hWVm8dkiRlWffR1J_C`p%^-{eZbqS>+`SgAy=3Lq+@n2fls zEkVv6CdY-_5F^vUo^^8pmS!_~Qq}Ys+^Ib#oC7M$fOR{? zQhse#j9D=UFt?f%)5xWG{eO|=_sH^l>xXSG+u9t@IXdhg$+?iTf%|~GS^9|kynDI$ zF4wazpKzA{Prk|dZp+s!GU`iC{?9H%ec>4yB{14V=`%it8ZCMq7we?Ch$Ay*T8Uly zX0Q99zLGLaYd^6hei8LmKQlAN7pJCl2>14Er8Q}=Jz6xVRY67_|O*-_Knv0E?XV)drT zwkaJ(k@||?=|z5udrCO`PU_8r$;8gs{Dk6DM&E-PMSTWLqvXt?UwdYvOe-{{=JEA$ zJ+HMIv&1~UK07dER*!jneI`~T#}=E%*UyNWmTiml#av7^g|DCOYRp2tnTrLk3*^KS zq5{31iygckh@q_I>n&XDq)A}^lGT`bc>dpmP9eEd`kaK^TgCfbFSu%iGyGHheCLqk zaYu99ynwuN&XtNUS(|o6v7-Oqi%AIG7!5zJ(4JfHj zGi9Sp={f5SYk`#J{2g&ovu)q$^=kl^rl*<}uCYA4`bMCo>8WNziz|S}8vxW#aSq2= zJvO_md-aA^%DHxSyhc8#Sq-=}-NCGIaYk6R3P?{=%m~v5(o*l;lp0RIkCVP;C5LXK z+Buo#bW?d#!%6m3UtHM&;?tb)O}LAhdsdUpg(WKhGe|LyWW`Krf~PJ!UbGybsrMVQ z&s-Q&Eqc{5fTiAV$PSCWMeS1Hq~5)qku$B`i2MH~=nf?BlfEdq-9d3oEOlwZ4}>QE zUCy66mpI;If8O4ja~Jn(ZjJ3;>qYAh%R`p=u)|yZ((@J2td3&oA*=1Mn@!$aQ_t%H zD4LfY87mW0m`eS?)Iw3HDK}l5a?3Nl{1~uppvY$EmFce5di7Btq~7$L#fq$jM*y^g zqLidInE^C))T#C`KvH*fGef3Sc-SXb90F9D9po%}CWl7q4gw|pA%|HhT6q9iX*SE^ zt@muKB;of{PWWt?la0rkeLzXSD>Q?cX)Ol5suM_QHo~TNg=Sh)px5mMPMSsO8l0&; zoT@#PH6_j|KF*w6lQn&a*?Ti^w$rYZGIHYLUcMU;X*NMJNjX{6D|P`P^_nPM#Pnib zxf3Yqd-rQ$R__2zn(eu`cTdNhUUU|02T+<<0$u|YmmTjmV5C{RGcqO%&sIRBS$L*< z^`yg0&U4%Zlr(GetduD=4_^OYV7nK|d!$deUv+O5?}7XOZxTMizv8TN+-4uQue9CE ztaQ?|hn;cqf7+i@{%gN|Q{XN_y=q-EHH0hV5%r`B;55M-%Y|-8co)<`$;h)3{Gd31u4`oP8HolIs}$~CS3=QYp0 zLbBn)SU@@TL5ph$Yg7;OsrUc0fu@bK&BN>e9jg@LU``tlj6O+NPEYsq2G7MvfzkK-9Hy#|E zz5|vuxKlapOr5LLq1?bo*3UA^0ml}lR=VF&VgHTPFMQhmHQp_B!WVR-1SkPYfD-us zO+ecw@%e>?Z1_ab-O;B8{q9cHANh2w-QL!^v(34)b>q z{l}e$)Z;byfatFU)nmbk2V6w;^mx$`&Z_9?)lR?Kt@>4Ory7W;sPc4Gi`BOeiF|%` zHhZUv!{qjN!hidO(11rgDDB;Fp-!K_3#sq$yS<&gYM{pHj)kz(2Re@hBcb*C`s;%} zXP?K5gXs-;f*zmOsUA~12ZL%?(g4;VX!-{5jG=*R9Yg^-7&$ZgTLwDularhoJv@4H zH;D84bgc0c(NDw4ShIJqzXOopJlH>gA_vZh{BY2h>daK<27S@MPCIUr#AQ6Z6QWZ` zj$$-&)}YsOcuhJ^uF^4cA(Zsw{Bpvj9>U4v0$;3p0a#3HO)7Oo& z3_9Bxi5y7H#ynH6!*KgiMsxb22ZBhEq&Hg$x2^fqq!`ptloc zl>iDur|*dBclW4u(QhNg0_lVVNvBb;=C_rnN;BUXV;xNa|KtAy-kWdj!U;cnQ*z26E9eIQBN{cmrWo|0rNP?>oeOhndZ^DxA zEX4Htq0mQv<_VIKPh9dw^?24(xKn!R`*+IpEYJ50k@2$Q-zysAPsuRDNBp+Kdx!{_T$-QGyu0B5uZ z;5R)1C)O~zR%(u4BXAsDqvuE^)}&W1sF>dgnNH7N;OOsnd%L3b6{?0KSB0`4Wlr=v zkwOGcbXG#93_uo5xTb#5=(niE(yw1P08G$T``ulU?2aPEaK)p&>ZHp>YNKo2K{e>< zSDok(ECwg6qwavS)33spP?uI$nx{$zD7IXU=o9slZKx@ym9u>Qf(5KL7|o24a>f;a zO1N?M8k96>gCj?1)g%kBYW+#A*kqWR(vY z_)j-VfD)htC;>`<5}*Vq0ZM=ppaduZN`Mmh`y*gxO)QW4|0d=4jPf>o(2WwH1SkPY zfD)htC;>`<5}*Vq0ZM=ppaiZ?0+PvGs_3_PG$^dOI6rz5z|y*fbxTDEl}S0vC})-P zS7!jJYD$0-paduZN`Mle1SkPYfD)htC;>`<63_`q=2BK41u%)`Vj(&RV1WZT<{Lqj(#4slmI0_2~Yx*03|>PPy&k*l^=em_N3B2P^LBfB>U&f#ym&I`^G7{u@q5|82VQ$u8&m_qKz*R=P@sO`c(50I zy3|h98}$34`}O+1%j0!*`uh6R$SW;foqZlS4vy+_dxM_NdU!ja2i~oxx&{Y4u3mTn zAH1*7uLcI-^_MEVGjBhHDNifo!p#Ik29FP@z#-^@x9oZYZX5zvAm|Pb28@CAZEbuFlsNkx6XuS@Nl2G#}i z{eOvxitbYalmI0_2~Yx*03|>PPy&PPy&C41k7fKfad=X@P`=XJ^2IqdHIz5sC=KiL*5{-a+syR zNN-4Iq~A!tkVd2@r0+`Kl1{iOYy_IvH0u@Bjg+7HoCiO-5Z7Eg)~iC+;vD~83RqED<6bA7G?|s;NFY?}N8-3+bR@j5Q_t-}F7K^))_ipSh-hkXU*hU}U<;dCv?uuQu zQPTEN^D( z?GrB0vdzK@8newd`u5P^g)hEzZ{RlnbHD!NMds`UBk<5=v%dS#1?Ks3=Da0z8-tzJ zt#DO&>#(o|Y|a)GFyVUSydF^yH-j^8b0p}SkoP8h#75-Y2w}Wgybc|49S)+0aM6Y5AKTf6NG231HZZJu-}9Ic7Va=wt-ho8}>55$i5c5tFA@f%L>OI>EHkI zskZSoYf-qlwTa~h&9K-CHm?=J^{6bg zfIFuJg;8uq-p$C{EUrfG)fj`g3b|KB;`bWlz6PTGMXR_HxmO~8tGEKWS70dF%fVf> z90zOsl~c8S5LP~S8F*ZB*;t6>55x^L_iobubo%^`N>eE8znd=#8r_SfI+c(VS@Tl3xuJsDGv z!ZJLBKJoU@D&_<;$ev}9!&(g|%hkg|71*3A9E+9U%&SB(S1MK@cLjC}^Uxvl@F8=N z_grv3`j&MLxaBz}aW?XsjUx7DaTapVibS{*xt%Ct7mMY{T^@0lA$J)*###z)xzvGK9@v~b+vw%|_FR-svT_sC$@uum^PkXRBHJ>~p8wO( znW5X54KF}K86LlI`rG3c=K1mQ-I0CXnuD&MGt6g$&B%5(i&@~v%i_+xyOFnMqAxRh z`3&@BhSO|SkcVQj$zZc&Q&qO$09THKd;Y9Nl)#xMapyk&B&*oL?X-XHzs=0ZgS(F& z<-pKr#eDH_t^+gPGkU3}#v2PE{-3;?* z>D-&YJ05yyY&@R{9nELfU2Z-Rg2$r>;6ll zAP9)C0P$`SY{+Rt&UHLW0um1u-MfYQPl(J{?rLh17CvBWpY3dahT@ZR&MGfbe5F`0W`Vwr`%#aDx04>jHVos;aR;8_Ih zW0FVMKabd0P7rdOp}D8g{Qm*R00Zy-`>XOl${WgS%FD`clwT@ODL+vjSN=tLL>X4T zqI^;LjB{E6qo0K+XwX#%cP^y*LO0kloI25ZqF266oBfllTF25?j zC_g7ZBag^GlpmA7BR?cRAb&~zy!2)+wn=qZH}WLo^F%? zB|r&K0+awHKnYL+lmI0_38Wzb)Td<+9KhzLo3Od@Mr`))$7bI?Z1(QOX3rjMcJIdK zh8wWiwF{e_JF(fZ1DoyJvDvl_o2^^1*|G(j>#xUV^JZ)|ZNg^bMr^LT4x9FNY&LAb zX8n3>)~&;)tqq%Nuf=BVT5Q&=!KSqpo0b-Anwzm%y&9WUtFXD|8f;ds#Ad|`Y?d#_ zX4x`qmM+C+$r5Z9FUDrkB5azPuvxeeo5n_L8XB;vug9jY4x8FqY-(z-S+D?``SY=< zuEwUS3Y*GGY$__SnKuucxpT3ZGY6a5v$2^q3mc~soAPpO%F3`QEybp!1e@YwY>JAo zDJ;aMpa7fvd~EXau*uEECMO4*>}+hZvard_#3myH8%4oJma%c*5fN6B@Sfd{jVNLx z2-w(c*zi0yRx36Z3pN~wjoFNi$;81J0G|J!JZ_bS8HY-u1SkPYfD)htC;>`<5}*Vq z0ZM=ppadv^k4*s0|I_~e$Hqrbqy#7dN`Mle1SkPYfD)htC;>`<5}*XG3Igb<659X2 zDx!*tqy#7dN`Mle1SkPYfD)htC;>`<5}*V=HUW{l1zt3-8`4rqm3crhtqlj9bxWZLKP9s+3{n#hIoNlJ4CeJ(%+THKnzg>y-1f%uC{IjEI# z;Z>xhOpdW518$eT5G|1Eg0ce-KH@Tj)IzQ)N)D8|BCENA(w;OE7tf#|u3KBch4&JO zWqpNNynwN)FNBNpWNh7D7c4sLb`1muT!Vg;J4&=UT(~`*#e&FUQY#@(hbZVPB9*VF z)^~Uima7JN1==hw+?HN(yr`iemL@@Bp=RU4*~BCos{4FW)rESjQyoC7j0apDZoCM% zRpYp@odA@$6o?v52wuD0)j1dl`uahLLu0tGnFJ9m z1QbZ53LIQHCvB7VsF7-?3*=>K*<84q0HBoeKvbqCap7X3q721M2C2l15gCLinw1MH zWUv@(01K(Y4uH5i^^9fGST4*9^}7P9KTxlBb$QhKL%1BOk0x-RKk8BI@dnkNNa<7? zgqk)`ALu#+o!;ZYUZ1zNOYKy>LBB7$U$5^&$I=yVE(W4MU2ljH(d=Rhm^Q}x50C~cPd<{)!ys&cJ-+c*Lr(ohgQyoTL~n&l;RRvBil(8uMvTsKwwbS6N%1Ew@{KT zCEK1$DldWH60Lv>HxY~Ch{Sl8(E#sS$R_!EHZfQ&lMBxyAlNscM#>QAule2mYEbpN z`rQK%%`URhoIDQ)2B3ke;$9?3+@+Op;gtlarOe3?(-DcFZl_Sh#e-C%X7aFZyxudGHfu;t7bF*mW(w*D ze0YE=msERe3TcK0d5+e|g;fFt;ADBm^4jQ*&7VOx1r7Pl*OqW$-&G>nfV!GgzhyG& zcqdIyri;@jiyOol=q(~OiW;G3P?DVvRY|-YoK)4VBUKn0dw5CoLDp?UQ*g!19~tFV z`91ll;~j@b`Y&mh{Tcfr@n6N+!q)TBI6QabZWqA*+?YPZj?x_W&+bOVQ0kPC7a&%B(;^)M=_`cn4~CU zT7ng{m~bW`HAW#O8H5m+76~37P+fyTPaldKtAh-U$m~#j{&z?M9p;&jmDntmCfPv& zfyyE}CJZ+zxL~B(9UV8)7!l-HW*$hOvsdkR2TGjpKB zKJz-_NFWQHFmsGHH1i?=1RAl@%qB7rCd~h9EDI|5nWtc=Y*GKefcXNW?2vycS2^yI z{v<88-)EP_KH+I$j_nitui#GqgO<~lLe6h~!CY&)lYO0C0Vn*8Hm$M=nCzH&CU8fx z+Z*(BqA|^B%~WX>3qk3&G*+tDn6nx|==$^(iZbM!2GF>1<~5==-}Iw=c0H&hFpxAY zm3nlS)`3U@14+{niK2RLE$G`k^HHsj#!WMO9kBBv))kLm=6Ng znHM;D0L3_kWppP_XK9P8L9*}akZh>Rwc0As?INH%UUhzyr$MxNm7sS^dh10=*jWKO z35L-nJUg7SQ_4fi^4dXJWBMqI)lNkl$RxL<$P!Dc;`Jbo zK*b&@AQB@qQC;aeP)A_=Ai28O*tPx`fL723`Uu=Da0Puhqh1Tr2xQch(&G7HEhr;V z{7!l+OZ-MO{Z>bGbFo-dEjKCnySfiJ>fL5m8<}bWSgZ4aU9DkC<)G94)O@hh8SzRRQh5JOP7I2!mXK9A`!%r zrDWoGYKXCRgL4VUBTy1fAuq8~DOwB?)1qk;jc2%HDc-bM1me=7X=4y)XxfPEI(TgL zVaD9b9X9{bwv9i@OV%#SzgaSr-SR)nyhD|KDizs}i?52Sh5Kw5n1{`aO9$QLE#^F0vXw$`EsvR>6h0q`6+;T1hM`>-j`~ zVj=mHVj!_Xb8_Le>4;LV3g?n~e?zRQP6{!h%{Y&EHc!%^NYJ>Ccyf&NQsYBnvCf~~ zxw@XzYcOJwol+uXmd(T-@7D8k5_Nh$*+lH|?o{FulHV5MrS|j&Nt)9nn@rKiUroH! zPK8oWjjhB>?W775l4Ofk#f5i}t^KBV^JtS+$%VJ2v(o7OqYESR|MxOVhkRNtb9_R2 z73TlHW@p5kgb|_47UuuJueLs5xnSANJ;^OF51VsL$Jw{ojm*7&(=M3SsKU5O&&*FO z^WP|G_2k_g;?qSHyWT!vP9 z69^+P?GS4jC+T1qr@!Xh2>M9Q7bn-3aN|?ieo)yu^C|8M6eB88Nil052qZ9zIF-PJ zR+Cn`mrPQ`^RP*xIZ z0+awHKnYwG1W4VDm8#2;&?eZc6>;IE1P0$z=`(aF_mG+jnnK&e4&`oAv!+*62(6VH zNUhcz?WZNYi_Q)&(+UfOQkwpzLYdSZRXD;D+vl;irGAgVMpBFOOf3%*({-fQT27@* z?^w4J&4P(BnozoKAa(1Efm*7$c0J9lOoJ?uN+Tq^6{K#PnG&I%`mP~bMNQ{EfK{aK zR>1tOaD!%SC8GvXtME)qWpw_(9`*kv+c`$rCqFB%ay;r-Abm?Jx1SJS6I+D);S0J^ z0+awHKnYL+lmI1gl@rkBbK%{DdhGhD&T8`KJ8F4M0;9E)g^TH%SbI8kNYr&iRe`<5}*Vq0ZM=ppaduZN`Mle1QH2owqCfgoxr21`1y~3@fBBE hQ4dHV@D$V(4-@; ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +144,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +161,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/configuration.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/configuration.py index 743419b4a..e8da96ad7 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/configuration.py @@ -134,18 +134,26 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if client_id: + if type(client_id) is not str: + raise ClientConfigurationError("client_id must be a string") self.api_key['client_id'] = client_id else: raise ClientConfigurationError('API Key "client_id" is required') if client_secret: + if type(client_secret) is not str: + raise ClientConfigurationError("client_secret must be a string") self.api_key['client_secret'] = client_secret else: raise ClientConfigurationError('API Key "client_secret" is required') if module_secret: + if type(module_secret) is not str: + raise ClientConfigurationError("module_secret must be a string") self.api_key['module_secret'] = module_secret else: raise ClientConfigurationError('API Key "module_secret" is required') if provider_secret: + if type(provider_secret) is not str: + raise ClientConfigurationError("provider_secret must be a string") self.api_key['provider_secret'] = provider_secret else: raise ClientConfigurationError('API Key "provider_secret" is required') diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/exceptions.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/exceptions.py index 9fc3ebf15..c244c63d0 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.py index bc946009f..30244c89e 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.py @@ -389,6 +389,7 @@ def issue_collect_request( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_collect_request_mapped_args( body=body, reference_id=reference_id, @@ -501,6 +502,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_collect_request_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.pyi b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.pyi index bfc2e47d0..31382695e 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_collection/post.pyi @@ -377,6 +377,7 @@ class IssueCollectRequestRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_collect_request_mapped_args( body=body, reference_id=reference_id, @@ -489,6 +490,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_collect_request_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.py index 40bf7792f..31a3e5160 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.py @@ -357,6 +357,7 @@ def get_transaction_status( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_transaction_status_mapped_args( path_params=path_params, transaction_id=transaction_id, @@ -429,6 +430,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_transaction_status_mapped_args( path_params=path_params, transaction_id=transaction_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.pyi b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.pyi index 5f0888639..10f932a94 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_transaction_transaction_id_status/get.pyi @@ -343,6 +343,7 @@ class GetTransactionStatusRaw(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_transaction_status_mapped_args( path_params=path_params, transaction_id=transaction_id, @@ -415,6 +416,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_transaction_status_mapped_args( path_params=path_params, transaction_id=transaction_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.py index 21e4bf0f4..30878cbc3 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.py @@ -401,6 +401,7 @@ def generate_payment_link( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._generate_payment_link_mapped_args( body=body, reference_id=reference_id, @@ -529,6 +530,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._generate_payment_link_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.pyi b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.pyi index f9bbd9f8a..aca46ae09 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_link/post.pyi @@ -389,6 +389,7 @@ class GeneratePaymentLinkRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._generate_payment_link_mapped_args( body=body, reference_id=reference_id, @@ -517,6 +518,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._generate_payment_link_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.py index c410a199a..8bc258734 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.py @@ -377,6 +377,7 @@ def issue_upi_refund( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_upi_refund_mapped_args( body=body, reference_id=reference_id, @@ -473,6 +474,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_upi_refund_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.pyi b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.pyi index 86d4153a4..46bf69e2f 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_upi_refund/post.pyi @@ -365,6 +365,7 @@ class IssueUpiRefundRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_upi_refund_mapped_args( body=body, reference_id=reference_id, @@ -461,6 +462,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._issue_upi_refund_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.py index a359a34e2..c3f2e638b 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.py @@ -371,6 +371,7 @@ def validate_upi_handle( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._validate_upi_handle_mapped_args( body=body, reference_id=reference_id, @@ -459,6 +460,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._validate_upi_handle_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.pyi b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.pyi index bfa208705..c94639172 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/paths/v2_payments_vpa_validate/post.pyi @@ -359,6 +359,7 @@ class ValidateUpiHandleRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._validate_upi_handle_mapped_args( body=body, reference_id=reference_id, @@ -447,6 +448,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._validate_upi_handle_mapped_args( body=body, reference_id=reference_id, diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/schemas.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/schemas.py index d2dbf8e99..26448662f 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/generate_payment_link_request.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/generate_payment_link_request.py index 136744927..9738fa2e4 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/generate_payment_link_request.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/generate_payment_link_request.py @@ -27,6 +27,7 @@ class RequiredGeneratePaymentLinkRequest(TypedDict): generate_qr: int + class OptionalGeneratePaymentLinkRequest(TypedDict, total=False): expiry_time: int diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_collect_request_request.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_collect_request_request.py index 7a809c1a2..9875c24c6 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_collect_request_request.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_collect_request_request.py @@ -27,6 +27,7 @@ class RequiredIssueCollectRequestRequest(TypedDict): purpose_message: str + class OptionalIssueCollectRequestRequest(TypedDict, total=False): expiry_time: int diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_upi_refund_request.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_upi_refund_request.py index adb1d24cf..ffa704720 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_upi_refund_request.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/issue_upi_refund_request.py @@ -19,6 +19,7 @@ class RequiredIssueUpiRefundRequest(TypedDict): reference_id: str + class OptionalIssueUpiRefundRequest(TypedDict, total=False): transaction_id: str diff --git a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/validate_upi_handle_request.py b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/validate_upi_handle_request.py index 4993c35df..4d294647f 100644 --- a/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/validate_upi_handle_request.py +++ b/generator/konfig-integration-tests/sdks/python-decentro/python/decentro_in_collections_client/type/validate_upi_handle_request.py @@ -21,6 +21,7 @@ class RequiredValidateUpiHandleRequest(TypedDict): upi_id: str + class OptionalValidateUpiHandleRequest(TypedDict, total=False): type: str diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/api_client.py b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/api_client.py index 1fdd3ba45..4c1b28994 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_enum_parameter.pydantic.problematic_enum import ProblematicEnum + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/configuration.py b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/configuration.py index 1ff05a82a..181f006fc 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/exceptions.py b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/exceptions.py index 391da19e1..f1d3792c0 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.py index b9b548016..64abfdc4b 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.py @@ -336,6 +336,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_parameter=problematic_parameter, ) @@ -400,6 +401,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_parameter=problematic_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.pyi index 344ab11d8..45ab31812 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/paths/simple_endpoint/get.pyi @@ -328,6 +328,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_parameter=problematic_parameter, ) @@ -392,6 +393,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_parameter=problematic_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/schemas.py b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/schemas.py index bbec742e6..e477835a9 100644 --- a/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-enum-parameter/python/python_enum_parameter/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/api_client.py b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/api_client.py index 9a81ef97f..e7e24ab0a 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_ignore_pydantic_protected_namespaces.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/configuration.py b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/configuration.py index 69fded6cb..3e5a4a06d 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/exceptions.py b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/exceptions.py index 716734412..9b70716e1 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.py index 043fd9fc5..648bd5a9d 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.pyi index 5f61efdb5..b4eb8c833 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/schemas.py b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/schemas.py index 0fff7487d..455b15af7 100644 --- a/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-ignore-pydantic-protected-namespaces/python/python_ignore_pydantic_protected_namespaces/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/api_client.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/api_client.py index 3c76a2133..41808cea2 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,18 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_invalid_response.pydantic.dict_instead_of_list_or_scalar import DictInsteadOfListOrScalar +from python_invalid_response.pydantic.invalid_array import InvalidArray +from python_invalid_response.pydantic.invalid_array_array import InvalidArrayArray +from python_invalid_response.pydantic.invalid_object import InvalidObject +from python_invalid_response.pydantic.invalid_object_object import InvalidObjectObject +from python_invalid_response.pydantic.invalid_scalar import InvalidScalar +from python_invalid_response.pydantic.list_instead_of_scalar import ListInsteadOfScalar +from python_invalid_response.pydantic.object_instead_of_scalar import ObjectInsteadOfScalar +from python_invalid_response.pydantic.only_one_property_is_invalid import OnlyOnePropertyIsInvalid + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +107,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +133,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +150,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/configuration.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/configuration.py index f44a7760f..16af52980 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/exceptions.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/exceptions.py index 8670775ef..0f1b6e160 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.py index 8dc7d18a5..02205ac47 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.py @@ -266,6 +266,7 @@ def dict_instead_of_list_or_scalar( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._dict_instead_of_list_or_scalar_mapped_args( ) return self._dict_instead_of_list_or_scalar_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._dict_instead_of_list_or_scalar_mapped_args( ) return self._dict_instead_of_list_or_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.pyi index bb2b43948..edc14dd49 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/dict_instead_of_list_or_scalar/get.pyi @@ -258,6 +258,7 @@ class DictInsteadOfListOrScalarRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._dict_instead_of_list_or_scalar_mapped_args( ) return self._dict_instead_of_list_or_scalar_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._dict_instead_of_list_or_scalar_mapped_args( ) return self._dict_instead_of_list_or_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.py index 7c18655b6..6cbaeec7f 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.py @@ -266,6 +266,7 @@ def invalid_array( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_array_mapped_args( ) return self._invalid_array_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_array_mapped_args( ) return self._invalid_array_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.pyi index 28f407ef5..c966a4eec 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_array/get.pyi @@ -258,6 +258,7 @@ class InvalidArrayRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_array_mapped_args( ) return self._invalid_array_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_array_mapped_args( ) return self._invalid_array_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.py index 4f565ba97..af34ddcd4 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.py @@ -266,6 +266,7 @@ def invalid_object( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_object_mapped_args( ) return self._invalid_object_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_object_mapped_args( ) return self._invalid_object_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.pyi index 3c2638132..10dfb6ba0 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_object/get.pyi @@ -258,6 +258,7 @@ class InvalidObjectRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_object_mapped_args( ) return self._invalid_object_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_object_mapped_args( ) return self._invalid_object_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.py index 59ee61781..60b66d019 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.py @@ -266,6 +266,7 @@ def invalid_scalar( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_scalar_mapped_args( ) return self._invalid_scalar_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_scalar_mapped_args( ) return self._invalid_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.pyi index 97673fab1..890b3c74f 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/invalid_scalar/get.pyi @@ -258,6 +258,7 @@ class InvalidScalarRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_scalar_mapped_args( ) return self._invalid_scalar_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._invalid_scalar_mapped_args( ) return self._invalid_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.py index b09e72383..0a12d5c4a 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.py @@ -263,6 +263,7 @@ def list_instead_of_scalar( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_instead_of_scalar_mapped_args( ) return self._list_instead_of_scalar_oapg( @@ -317,6 +318,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_instead_of_scalar_mapped_args( ) return self._list_instead_of_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.pyi index 689a0bfa1..c746f1d13 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/list_instead_of_scalar/get.pyi @@ -255,6 +255,7 @@ class ListInsteadOfScalarRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_instead_of_scalar_mapped_args( ) return self._list_instead_of_scalar_oapg( @@ -309,6 +310,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_instead_of_scalar_mapped_args( ) return self._list_instead_of_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.py index 6d6d6e1bc..9bbcd6f5e 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.py @@ -263,6 +263,7 @@ def object_instead_of_scalar( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._object_instead_of_scalar_mapped_args( ) return self._object_instead_of_scalar_oapg( @@ -317,6 +318,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._object_instead_of_scalar_mapped_args( ) return self._object_instead_of_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.pyi index 76c108bff..e046a9dd4 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/object_instead_of_scalar/get.pyi @@ -255,6 +255,7 @@ class ObjectInsteadOfScalarRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._object_instead_of_scalar_mapped_args( ) return self._object_instead_of_scalar_oapg( @@ -309,6 +310,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._object_instead_of_scalar_mapped_args( ) return self._object_instead_of_scalar_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.py index c4dc41b59..015720e83 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.py @@ -266,6 +266,7 @@ def only_one_property_is_invalid( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._only_one_property_is_invalid_mapped_args( ) return self._only_one_property_is_invalid_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._only_one_property_is_invalid_mapped_args( ) return self._only_one_property_is_invalid_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.pyi b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.pyi index babf9198d..f7b5f0df8 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/paths/only_one_property_is_invalid/get.pyi @@ -258,6 +258,7 @@ class OnlyOnePropertyIsInvalidRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._only_one_property_is_invalid_mapped_args( ) return self._only_one_property_is_invalid_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._only_one_property_is_invalid_mapped_args( ) return self._only_one_property_is_invalid_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/schemas.py b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/schemas.py index 28208a3ab..1f9060f4e 100644 --- a/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-invalid-response/python/python_invalid_response/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/api_client.py b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/api_client.py index af22c07e2..9c0097216 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_nested_array_items_ref_in_any_of.pydantic.simple_schema import SimpleSchema +from python_nested_array_items_ref_in_any_of.pydantic.test_fetch_request import TestFetchRequest + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/configuration.py b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/configuration.py index 9526643f1..d1d0e4c82 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/exceptions.py b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/exceptions.py index 181cc75b5..ffe8f4a16 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.py b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.py index 0bc64d7f9..13b9367d6 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.py +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.py @@ -327,6 +327,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) @@ -391,6 +392,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.pyi b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.pyi index c57498c73..c3289eb31 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/paths/simple_endpoint/post.pyi @@ -319,6 +319,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) @@ -383,6 +384,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( problematic_property=problematic_property, ) diff --git a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/schemas.py b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/schemas.py index de02febe5..1babcfe89 100644 --- a/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-nested-array-items-ref-in-any-of/python/python_nested_array_items_ref_in_any_of/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/api_client.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/api_client.py index 6d04f5e5d..93a717591 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,47 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from newscatcherapi_client.pydantic.additional_source_info import AdditionalSourceInfo +from newscatcherapi_client.pydantic.author_search_request import AuthorSearchRequest +from newscatcherapi_client.pydantic.authors_get_response import AuthorsGetResponse +from newscatcherapi_client.pydantic.authors_post_response import AuthorsPostResponse +from newscatcherapi_client.pydantic.cluster import Cluster +from newscatcherapi_client.pydantic.cluster_articles import ClusterArticles +from newscatcherapi_client.pydantic.clustering_search_response import ClusteringSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_article_result import DtoResponsesAuthorSearchResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_author_search_response_failed_search_response import DtoResponsesAuthorSearchResponseFailedSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_search_response import DtoResponsesAuthorSearchResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_search_response_articles import DtoResponsesAuthorSearchResponseSearchResponseArticles +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_article_result import DtoResponsesMoreLikeThisResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_failed_search_response import DtoResponsesMoreLikeThisResponseFailedSearchResponse +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_search_response import DtoResponsesMoreLikeThisResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_search_response_articles import DtoResponsesMoreLikeThisResponseSearchResponseArticles +from newscatcherapi_client.pydantic.dto_responses_search_response_search_response import DtoResponsesSearchResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_search_response_search_response_articles import DtoResponsesSearchResponseSearchResponseArticles +from newscatcherapi_client.pydantic.http_validation_error import HTTPValidationError +from newscatcherapi_client.pydantic.latest_headlines_get_response import LatestHeadlinesGetResponse +from newscatcherapi_client.pydantic.latest_headlines_post_response import LatestHeadlinesPostResponse +from newscatcherapi_client.pydantic.latest_headlines_request import LatestHeadlinesRequest +from newscatcherapi_client.pydantic.latest_headlines_response import LatestHeadlinesResponse +from newscatcherapi_client.pydantic.latest_headlines_response_articles import LatestHeadlinesResponseArticles +from newscatcherapi_client.pydantic.more_like_this_request import MoreLikeThisRequest +from newscatcherapi_client.pydantic.search_get_response import SearchGetResponse +from newscatcherapi_client.pydantic.search_post_response import SearchPostResponse +from newscatcherapi_client.pydantic.search_request import SearchRequest +from newscatcherapi_client.pydantic.search_similar_get_response import SearchSimilarGetResponse +from newscatcherapi_client.pydantic.search_similar_post_response import SearchSimilarPostResponse +from newscatcherapi_client.pydantic.search_url_request import SearchURLRequest +from newscatcherapi_client.pydantic.similar_document import SimilarDocument +from newscatcherapi_client.pydantic.source_info import SourceInfo +from newscatcherapi_client.pydantic.source_response import SourceResponse +from newscatcherapi_client.pydantic.source_response_sources import SourceResponseSources +from newscatcherapi_client.pydantic.sources_request import SourcesRequest +from newscatcherapi_client.pydantic.subscription_response import SubscriptionResponse +from newscatcherapi_client.pydantic.validation_error import ValidationError +from newscatcherapi_client.pydantic.validation_error_loc import ValidationErrorLoc + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +136,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +162,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +179,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/configuration.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/configuration.py index c8b773047..f19b86262 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/configuration.py @@ -139,6 +139,8 @@ def __init__(self, host=None, else: raise ClientConfigurationError('API Key "apiKey" is required') if x_api_token: + if type(x_api_token) is not str: + raise ClientConfigurationError("x_api_token must be a string") self.api_key['apiKey'] = x_api_token elif api_key is None: raise ClientConfigurationError('API Key "apiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/exceptions.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/exceptions.py index c2747cb02..a1fa2162f 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.py index 6631a59f3..23796833d 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.py @@ -1077,6 +1077,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, not_author_name=not_author_name, @@ -1445,6 +1446,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, not_author_name=not_author_name, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.pyi index ef087db43..5df23dee2 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/get.pyi @@ -1056,6 +1056,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, not_author_name=not_author_name, @@ -1424,6 +1425,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, not_author_name=not_author_name, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.py index cc7fc9e97..31e770aca 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.py @@ -580,6 +580,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, not_author_name=not_author_name, @@ -948,6 +949,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, not_author_name=not_author_name, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.pyi index bfffe10b1..1d92a0cdd 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_authors/post.pyi @@ -571,6 +571,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, not_author_name=not_author_name, @@ -939,6 +940,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, not_author_name=not_author_name, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.py index 94d55cd9f..2a7d62015 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.py @@ -1000,6 +1000,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, @@ -1368,6 +1369,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi index b337ad52a..ab18dab47 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi @@ -979,6 +979,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, @@ -1347,6 +1348,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.py index a6f60a935..6503be964 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.py @@ -580,6 +580,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, @@ -948,6 +949,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi index 0bc7dd9e3..49eb8e355 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi @@ -571,6 +571,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, @@ -939,6 +940,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.py index 0c7d8ab2f..13f69b885 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.py @@ -1221,6 +1221,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1661,6 +1662,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.pyi index 4f2841601..7a026a030 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/get.pyi @@ -1200,6 +1200,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1640,6 +1641,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.py index 713678dfe..ec81cc774 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.py @@ -634,6 +634,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -1074,6 +1075,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.pyi index 4ce7f28d0..726ec3e9e 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search/post.pyi @@ -625,6 +625,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -1065,6 +1066,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.py index dc878b8a5..6fb41645e 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.py @@ -424,6 +424,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._get_mapped_args( ids=ids, links=links, @@ -512,6 +513,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._get_mapped_args( ids=ids, links=links, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.pyi index 5be3abdb2..2bce33d81 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/get.pyi @@ -409,6 +409,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._get_mapped_args( ids=ids, links=links, @@ -497,6 +498,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._get_mapped_args( ids=ids, links=links, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.py index be3fa4f00..04011706b 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.py @@ -370,6 +370,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._post_mapped_args( ids=ids, links=links, @@ -458,6 +459,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._post_mapped_args( ids=ids, links=links, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.pyi index eb32bbe31..ee917d958 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_by_link/post.pyi @@ -361,6 +361,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._post_mapped_args( ids=ids, links=links, @@ -449,6 +450,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by id(s) or link(s). """ args = self._post_mapped_args( ids=ids, links=links, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.py index 658efa959..1162369f0 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.py @@ -1101,6 +1101,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1477,6 +1478,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.pyi index bf677d90d..e497735b9 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/get.pyi @@ -1077,6 +1077,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1453,6 +1454,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.py index d4373d157..02f621a11 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.py @@ -586,6 +586,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -962,6 +963,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.pyi index 0185b47a0..479a5046d 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_search_similar/post.pyi @@ -577,6 +577,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -953,6 +954,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.py index 3df224ebd..d88e1b72b 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.py @@ -472,6 +472,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, @@ -592,6 +593,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.pyi index 0e7434584..8ba5f4211 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/get.pyi @@ -463,6 +463,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, @@ -583,6 +584,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.py index 2de77029a..91a48ff85 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.py @@ -394,6 +394,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, @@ -514,6 +515,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.pyi index 1789ed892..b2ae1b226 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_sources/post.pyi @@ -385,6 +385,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, @@ -505,6 +506,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.py index 9dfbcd272..05b1d143c 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.py @@ -293,6 +293,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( @@ -347,6 +348,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.pyi index fb5fe425f..070dc3370 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/get.pyi @@ -284,6 +284,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( @@ -338,6 +339,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.py index 9b1d07b76..77e1d967a 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.py @@ -293,6 +293,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( @@ -347,6 +348,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.pyi index 30c95e31f..46e8d6a37 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/paths/api_subscription/post.pyi @@ -284,6 +284,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( @@ -338,6 +339,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/schemas.py b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/schemas.py index ed34decee..f24792f97 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher-custom-server/python/newscatcherapi_client/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/.coverage b/generator/konfig-integration-tests/sdks/python-newscatcher/python/.coverage index 378ad6b4a0b00e9a1ffe0b9c329062a003868ec9..35d29653dbffc6d4bccfbaea4562b5d2bc9cacf1 100644 GIT binary patch literal 131072 zcmeHw349yXwfB`Yl4dlck@q#WmBd+zHai<3KuAak1VWG%TV9B5Ig%VFgv1_& zy(vp5B|yMoDTJjBv?YbYtNr@%vApI%*rDMohPIECmaPd(LTr8K+>xx2WSh`ZuIQWj z*}7-$o#j9Od+v7bw(^{_8Uh|?t=HG&4mhWf6k;%tN~e<$BEmnqk;4iC7dZjfppgd? zMKW>QYP;h+B3XV&92eV{IZCA6_R-=?Qj>74c&F7ZR6~G%=nUu#=nUu#{O@K!IY+W) z=jIxMTLbQOjh=wdUG4FyzxD+y7R@_%k@MVn^Uqr3RQ;S|ZB95!N}ThYK5v_|#p83< zHZ*#i4b3$T)$Tw;bDc9#?}=R9>i5)OK?iHR3V8fxIKfTs=~(c)`pa{D$r z*LyZkpcjPS7VvBes2=bTPeWZZUf~=YzI~k2=c)DhJk8Y}zlvgPL(Mqbxb5vWYj%3N z;VKXPCbzE|{=}HC0gvdXEUASDReOCkh<=^V-CSMo@lSBN`@gW-3ph6g)UWk6L!iOi?DTB%RJR5^H3NR&1SBnT0D0Q4foE0W2UV$ehTo-OCwlV$cZM$y z-&_men!OQPqc`HK;bw}txwUB>P<}~kQwv58+@ZcW;2rGF!R`%s!ykLnaWg<%M!z>E zIwO>0jH-9FHaBc&_4G&n1ZVWl3G_3Xy%U`H5ugF1L`!ygx`BXJdN%ntG(vsLA4Fc-!&P2q{~xzYj#nQ;i?T(QIHOlgD+w+|DV(;L1JkTTUa1Pd6P>l(f5Vs(vbjNbzZ1oDE&Wwou% z)tFTL_zl(GjUJ!7&NDF_s%8tU6$w;lvS7(xR5Y0C^s9hta=&O(axK>E{Cq=DplTG3 zt*~Q_QK3jo4v>vTf|@*Tf2%K&kqnhdM(&8_l94nL4uQ`pv0Ad{=ncTfm@V0}G6w^W5L}b-*Rp+$ zkwU&Im$KgknLhrTVj!bW6!Mv#%_SS%jgXtPxEp+sWFZe$O8_TcSmTC^-Rr!q0jj@v zO4Sp~o+w`R0nzga_i)uXdO0NTDw)`_AzRofAZa?Ni{xQyVUT>qv-K>@k zaK{oqytBdYq!IrhEp#x9VH(=(b#^5@Yg~(Omx{hs}9Z(t^ zUlI7z51j#>0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mzfqy>+Oa`ODitT@+<6YwT7=H9a zXFz8_XFz8_XFz8_XFz8_XFz8_XFz8_XFzA*`^kW0G!-}^Lp&xq45s|-@F0L06HlEu z!v7Gf&>7Gf&>7Gf&>7Gf&>7Gf&>7Gfh%g|T3Jeh| zfYD~k7s5sWGhASG9Ky>A9bY*+n(8HUxQ8*gEMD4Dq&36_?w^2212(wfbU?&kVdcXM6o;)X!!dT(=WLtSZ|rx~Vq z1-!nnM+u$%06s9eq$J?+2mGb}n)UwDmd$~B@M-q6`C;}bOwsU#y-GD+?v@5ubz_64 zIRJq*?&d&4b*aChsiD#BbJcjOTbm#R=AkI%Ie@E;Ev}k?*X8s0TVR@-$M0%_32m;% zhV>p7P6_D`fO$Lc4KRZVu54|j*k@$}_ASYTy%A>M_yewbkGqCWY#a)GQ5K+Iz!rUV zW2-;l@xdHkm)`@EtLpm!qi$qove(%#!bt4<5toz!xC)YjIfRp!4sgoZ!hwmp^pXTxJ)bBibLBfdfXqyf-7m2@sR zhD{vcl6L-5Y>TKp6Qx+RL54~?0NAkPD-j0MkA!SBM@}aWP1=Xg$x*VQb-;#aswLsh zpZMAX*$&_`l}s*J!bXLoU69Tb0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0iA(=Uj|GD6S3p`e}m%$fj|Aw8PFNf z8PFNf8PFNf8PFNf8PFNf8PFNf8PFN{H)OzMvI{u>-{3foUzhJVEA3V4>0Rjs>1pY4=|1T;=?3XaX^XT$s*zSm71C5`tTaqYlZbd!JS_e}d|7-}d`kSe zxL4dQ?i8;UTSd2czPMB@7fZ!aVxE{Hnr+8zAKBiuy>2^Td)oG-?H9JawocnE!e50R z;Z5N=;UVFCVYV<)$Q3yL@B9aR5C1CvTYf+PFn<^SV}1vpZGF+&Wqr(gxAhk5_14R+ zms#GjJa2i>a>(Xwh<4->-V# zw{{fwV)zys*wKgbi}=&N5`ROeyo4O4GW|K5zWod8P3Wyfd^=|l(%ShR!L|*gtZjVH zV-Gf_Yz2A5R=($gRUXREG}~nudKup{?V(HfEqKosph>zEq`XU!k=0gX?q)cfx*5-M zdJct7029C6-?ZjvJ8_<~$!rjm5u0dOM`+5auPZajVZ&+9%v^3Ib3O^Z_}psi2V{>m zC-<+F1>|Tqz-{l-5_yI8gnm+f8@#QojmAd%X|E`K4Ttt4-HSq2Vw5*RVBtm#q_L;W zZ3O_q%UY4>$JX{??1eD)+9R=d3>k7A`1q^e4Dt8p-JQFS`0t`jQ%31e*KcB?htk_? z`W(Z$+Iu@IDoF8P@Z=p64LXW)JAKCOG(t+LcO`nON88Kjh9g~#KT7~UNDk}~{NQHz zQMoNX^zzjU8_;V5DmLE&Vpt7n5n9_gl;R$rqiUM^yC>9f{O?^KM%Yll?jSzw2>f?F zfD+YM>W62PhIR+uz6Z~({CfPn^{A|ufRuHKs;mtlk7&>;Ydwb6tIAr3_te2XLM=!c zwQ$exMGuHM9=!eM2EGQbs6lnE1}U!^89{Yk2WL~);aP$@yQw<6Y1p@<&QVCWb`+?qEr0ftD2 zd=Uf}UWCDFf^e?E1W~yroFGEEQ)&-<8R|ryvyW_j=ZgXVO5Q*5r`?_6XLwcQ*!OY# zT(^!s!&eZh)%|}Ywk;O|Wck89!Uf=FTtHQRHF~YC7tTko^HJqf&jYdeJWWn+;#YxJ z+A6-ML_Qa!!gJNH-eZ+cTZ!=|twfKqP%h@)J7)D9RzmRcyFR5~^h=Gt?~loKO8WEe z3jYeK{VTp(?LP-U>m1bNNo@MIRmJ&ECESgVoW(5uRk3bdhT&kN8v#weKGiqU5q|Czw8XFTl#6} zc^Z0-z2`5Lzqq30I59|zz%y?VdSd!n2xn6l();3ygB1&qzv2Znj3nm%oi{!zziOy- zOj64U1!LyKuQV}}rOlS^#$Z$ae0W{ie0*eL0+Q!JVBtIrJPgH*WT}L6xzZ?9fSXal z_w;2eU0rxB=~p;faI5KzmL8Tl2!GBV>uhjSW;@%3S@<2ZXd0P`VKeKkJSYoO@R}(g z%fhKBo{Azr8N{^7d{4SC2|XwAJ%>KvOVP8G?^(l7L}?;OX(b?yF2P4djt}?=7&?LP zd6GW`rBgsk8;{qG*Is8z9S45J<1~IIek|TF7H=Jc(ilKs8x2y{XufCts#bm!`i{cz zVw8#z;Yg4&MnZV2FapI9AX;t1LChMi-sQw=o%pOG^ev*kwnCH(shm;(@`!>cl$rc6 zyk{8RlaJTstM}xgoJVCL7vzjwxaWh^91x3h&|5uTGo)mL*NAM*6U8j>$;rZtUNi8S zaFUjZ@H0Tl$N=wFJ{>*Nk>E6x((vu6AZ4Y}H>RY3JR(K&Oq&Bk9W<1e@g5oOPPKzn zY>!^|pvfYEmn<1!oeP8D6tDY>iF9|K-_~Xg&agppxV+iM_k^;J`r z?djgRM>>ypK4CaJkB}--W$7?{yk~ALA%BxTdH?sDJD%zdWs{EfZ1PNB#nuj(MNM^C z^V1OuVMXF&_z%59g(kTphtv@%rJGEjGG&cPnncKfN6K5ex%YFsxx=Kxa6=s#-F;+E z`nncNm9dc!%dW@+4=kS!VmFQ<2fqSRLCEwf8fYioAvZBjA}6e5+a0&%RdopDlMn>G zIj=p_Kn%t&O{9`^6yg1(z9SWWbGAOUFPH2o%7-~9A9KX{X}jspYwF&+;?~;cD&s}r z|J@r*=`B}g?;3aQ-Q@A7&E)E1@_V-)TlQZ;PxtN5KU*vaKxKvid5T%!QRGovXvHj# zxAHwl(sS^Ic-Sgy-y6Q}hMJkFI~P{&Jl*igO9a@=AywT~mG-Ji@n{C&Lm9-7f_JPw z)YoOVzypU_0CAVplV`A*;WW# z2ispvn_b@aVPW-Cp~u>e_8eI@_jm70J*4H$cRug>u!wZ@n&AJ-E-t0pA@}y~b#zx= zAL{*TqpA0y*Sq8o9K>E}ItcMY$gA)4y<#|MIQUiT!6Gu15C}UA-rap<(jIum)(+GE zym0B0(}-ml_+= z`)Br#?C;xq>~Gm$w*SulwEaKq`|bPed+m4GZ?oTI-(kPPzRlidZ?QMn*V)(D&$TbL zpJuPHm)R%V$J(YzTbJBlGzm|R>JuLl1x>LFZ z>>Afd9a5XrEP14hq?OVc(mbh5DwRe{1yY72N=EUR_=)&F*f?Gj4~YLq{I&QfSUEby zAB#T}FBi9nKCwZp0$az~;v#XjI7J*U4i|GohiI|&+K$@(YJ1Q2mhB)=tRFf9Is-Zb zIs-ZbIs-ZbIs@Mx1K2rYB#)9uRpAlxh$`$O`&8j)xqR`H?Ez zL~c@ron)sf+(>Rzg&W8Xs&GBIUKOq**Qvq}$q!Xw2ic(tKOjF)g=@*Rs&EatMis6m zSF6HRv^`bdU~g_ZiyTsk3bxb+&G$ z&SjTTXUi7qTzV;WHgBfRrcKmoYopG_jnrvvrA{C~9lxJCJ|A^9Y@kj{3w69+>NGb~ zr>TiLjg8bU(uI<>Xb@p!0HQ$wBVYU-?8M;*7DI#pHFak;2- z@x|0xyOuf^T|}KVYp8SKh19v=0_v<@O`Y@4r_OojQD@aE>YRHnbylvV&WaV(Ip-Ye zEMHEYWy`2@_Sw`~x|BL+okg89&!o;7XHaL!66&0OI&~H=rp{@nQD@O2>MUGHodpZ1 zGk-pH=FOu{WhHegDyTDeE_LS2q0a2t)R{GlIx}Zdr@WjxWo6WvF@rkOr&DLzH0n&9 zN}VZFsB`M6)R{b)I+G?*r?iwh6DLxqq=Y&XCQ#>;Q>Zh3Jaxv6qt4i|)EP5|I-^HZ zXVfU_6cQwRQm3ehI)#PQDJY=Muwm56&!X=N_0s99h2m;RkkJui*z3fQB@e&>7Gf&>7Gf&>7Gf&>7Gf&>7Gf&>7GfNHzwr|38o1M;w>Jto>U1@9k$uzmkTF zLEDG6<-)IpBK`(z$hzM0-Po{TdwpS#l7{Ahrw(Xu@HUqO zJpKUex>>W{U)r)cP!B%Mo;H8AJ5XKk@rAugHD37c>c$37a{#yKjcnSfY95AZW7Myt za=}q-wm%&R97Lo~DdK|jSVKzKjTxC!)9MCg6c=2YlmN9+dqGm@-9S7-B(KKATFRQk z$nNjaxIJGP27B!$6E1C(&Qj7~&+jBc2QfKQad5%mtTDM<4b2S!mkR)uD|RlJ&$b+J z1-w|e0~+!RC6^0MVF*XFS$pd`f3>fn1xpo#_Joqb1;-@^G<8pDMD;l4TQiaaRZMja z!TpNiKIXK%)WjwQhoBx)HwZ6X<@flQ)G(r;;F-9Fq0V;m(SyG@izNCpgLw)Jw2Gp4vJd02OvgR zqCIFAn5276)YuF^B-yYsrR|u}Zz(tY)VkX8ig2r7=P$Q@ZoZM!aqn>p4F=OgCdqNS ze6{^WyIoo#?lKg8!=}HI1LY_i)|z2LqKx2zi-rjQZW^PSiU>7=Xe+toA+C~)@DGVm$%fX$kXL*cO=`8y zqP5~YfFKNv$*ro@7_eAbVxjhDS2fg2yiI@wmk)o{%|>0+JgEjuGLcHW zKfY{?lt*|)Ya>?bHYt_dcEixAk9D&<;I4yy0ZlC=rW$pJQpN>04E+V+8@}~^hk+<> z^7=fk#)kDCSD?PZ-yau=)RP@bITvhA9%YF)Y7BwhjcQ{`9_aCH7PTrknEGRNY>_ep z)aLv41ps`ZGM5XsCq3|5cSED6CO!rL|9oXS7xX4Q{&3Abno};o@&CD`n>aShpU6%2 zKiMykekWCkKNE9oJ8eX0;a}lrSOb0Gs3n$Wek2ftS^V2x8osIdnKi`Q> z-`~8tpp>Tq!%3A%o!m#Dc9f+6_ExsqaZ(YGQ0OX^4$vL*_W=5!^&KTw2KHyL{e(!` zj5Dk$dG=(v0FGK-NJ7Z@%5Jp>A803dcIk)p}}vHhO|TS_`+%kB0j>}F|+_#@lvwu!=x{4sv5 z^>J&qrOEuPc?@@r=_At$<5R|5Lo4|M?mqxP-n_#W@i$E=nql@fE%F5`f62jE*W_{D=}IcLJbdTs01l zb4h5m=9~i9rX@wB#z$uUcz`yGEwls^S%0;?U>u;UV2f@5BUnGakz)bhnMsB(LH)*z z0hB9~3}vKaF~$^DI2w@7OH!m*gp3#k0GA{g!1y$sTMQr>XN8(prpM>=`dp3PY9ugo zBw%CQaS)FUapjEwT#T)r^?^W(Yano=h6A`|Y_%?Ilo}v6>>n$q%yI(Gr0T)wA9?!q zy|~J$MS#A6Ez7Z{&96a^dRtxypxcre^x)Ra$pwJDE}5|>8j%+a10ymUGg*J-H&#g! zYELJj>NE3!`OV41{7HTVs{Fh>hyv^P0sNq@y(>w=!WNu(`!k8mokZ zbRZ2%fRcFzz-LnrpzsIl#SoSNE;g1`ic4c8QnF45ER&f;u{s(pzAh4}#HB3;VB?Yq z7-kFErva!b3_%TAeXCdm8J3A5vXe@y@s$nDd;?|rLg048_v{N$DW)v|;ND~ho>~qtOtXEQJGSjO8 z(P7yjmjfm?z4}p1+9(vt01%tHCk3R%Vx9q59859-tOvVV0}YKBNy2nyoT#0~(Fr+< zaT;J@Gx#vtft@!MKrl8``n3}PBZhp8t&AxEE-5;Gakfl0|O21W~ZsGwpZg4{ik z;qp}~prK6a>liMa_BH6V9e33X7dcd6CfE-niJ$CJoUk|^%SnCVmUU#lN__t;xrO2K zO)7hF3Dp%H%R}zs=aQS5E`Shkg@SBkF~jwd!iSf)|lm@e)!n7#8fhO20*ybVyI zMv8+bs5mVe^Uo#$oNYbyay$RB#dOp!jJ4<{6n+DD0b>2@I%Ph$eW=xr{)MX<{S(l& zl?`%zlFhe{x10}Z7Hv~Xx#0I}Nr&OE_ElW7;yYT1d61+WpG`Mo^=?5@L5$0dr0|=phpbaAJI$Y&S8~7P#+q(2eq@|txS4!Jmd3aH;an-K z0rSQ@X12Q01igw&07`K+09?uh;2^n3#Au~0SCss90F#Xg{cB)?&M0MWK*wh0?LY;0 zLZru28eQ%}8Bqn$*^HW1p`SzssHC|7B+Ee!1Fa1pTnwPtbP1@;g+ZYL4qFRY*i1T# z!7}hdjY`o)0B=DuWis*EVBQ))$jEf>4%GW`Zwps^x{dU*7G21UzGyFN0yu4#RPhCX zkWDEP?XQbRn6MVBlDC>!EDsG6({Seb0FKSDyC^tqFR{8mh>~?4;9@ggL^B+4fQ19H zRwV>~jGa%i(U3Sd4FwDcLKN0@(nOnYIFuu_@xCd0b?43-U&jxTzwJc(gfQ3?RGfbJq1vh^mzXHmDeC(OEelNfes``1jbKf+^-w;lyae44549EHP7ZV9O9T}D| zUKz^;S289p!L}7|(#IwG#xUG#wx7pAkpjTcxNUVs@=+Oy>T$Sj^_j_rFTMaC%dpdW z@Mw-p)1w%UH0lRAm`z}WGMWo6V;s*X(eX8WprPa6(HM_@5{Is8#aF#Fo&Qc{3Kwi( z%b zi)KNwb@7ucm?4!eRpxNPtxV#&^yG05YIr+SnZ^a1k{y0R75XfOMmfrQxE3_)+r7yIGhcpNNEzY7X_aTy-0(MVJT)i67ovm5!_f#Hu`7(F_?X4xK;STQDck^%<}p#ND5Qk0 zQe-YX>b|H20J51fLrcH}Z1KI2O0E|W&R{~}zzCzmrxa&1U}LjYkD8->J$-pi0Fh0K z9R#9=zx+l3$7Z@^G@Fa(urx9(f8=^V$7XAn!89-2m!_?8+l`QMBN0Ox0y zcw70z=^?-aaJLD(PZLg%(0Y--NGX^kDD10qoVzc`qRmW(j zmXhxQC~R^UEtG*ROE%*lNvd%i;aW`ljGu|e9m{P8ZAHd$!WRBLex9|{YO>UtyQTjy zj}xyZZu?$&Hg~hB*VGEPo!r52JvRFFLo6tEuaXKq5C43xdChu%Y0Kt7y|=lf+0*8) zb_ZY^Szp+zRO5ve9(Dap)zaGEW{Gs0k;}0|uarHc`05YYj{N|BHr75GkFi;3KXYF{ zs-qngH!Ze*X^1|J()Hfv+JE87Lj!!vNsd&3a*X^41{(ywg>fGLu*Sy5!eGb;wRDji zzqcc77>+(s^D%W^N1V}M3&SCt6xP?)WpJeKdWPeQhDHhCE@9YhFc`QG~F{%M91cr3o={el^((-}rPs zL;7QeNRgi~Tx4FQ2xl!T6S?5G8Sme;NjY?enb3>3Rqg*@NF2-MPMGz-TzX0xAzowq z+;*|>TVWW##rlqQuH`cGZ_N|94W^%(?8dVUH<7-$`Tx^lU?Ho%zyXShgk(8zBN2)V zB^8v0sqHGV6uV~iZegRA6d5>XV~qbNz5#QKG{p|k*(}?nLLVr*n65~G zDtSg?45k!``NdpCWVTq*H&KPbGmHY5=RkrL3=?EHsYMhcuJx7fd0ULI| zgvXmWU``OLjkvT0y=D+XreXp}Y{sQ&A;nwxlq|&vz}T#H7cTYGT2TVB6qr-RYRFs+ zGEFq5Dg-dG=?#z1)cS{z%xDKpY^q!X)XU>*hw+*l&&;bG(wR0NBN( zygdoP33V`R|6gs`OB|oef0v(^ACf!e8{{+O3VEt@T>6XjuJnTRwDh=ipLCmagLI{| zMcN?MNGqfYX{t0<8YZPlL_8`U7XKi=EIunfCH`F8EAAF|idT!RqFX#)Tq>4}rQ#?t zPfQWbw&S*sZ137$w;ixOZF|!83)@~>r|lNuuR@RTrtqBbkZ`^*TbL;13LO7;{sX>; zf0h3&zn_1Yzl;Adzk|=VzG&^TK4!h!dW-dX>*dzVEN@w!w>)UM*>aWT5=*xEg!v=$ zpUiKV4}i5|zxiJCF7tKfT<&e|0QUs9kGq%K&E3ddV|vc?xaoG&>827>ktx$87{4(7 z)%dP)txSnIU51|nAxU;vp{`^UWODT$8&pb+LI$~tYnfPJg|Z*LudKI0 zNsHcB@KqBH=}^2Gh0)}4zUS6ek>fQ1N*JS%Mz-@kYaNiO8-+p=JIFh{KpVIDw+=M*Z!3>#+@Hmuft!5LKK3}+(tV1 zo{!sGzu5VP?}cSA9D8DU^dc&`x~y8hj}|R=_5G^%eQQT?FNSZSfgOD)zlcBWEAcmE zrv8ViOn=U%Z~sDl7QMBIZ|4j`T07q(*tUU`wTVB)v?o7Nm{C(d&=nGJ$6 zViOJP2u(Tlb!8?wY&h+inaizY&L^Q4pIdGHfb6m6m?fE?`xxb1yfBCpV%&`-*5 zgSVBn(b#A|?G>f3;n04hdr`ZMo203u0(J3XnPsmaHOm8X9>Uu$$>qBAKVN-D!0XlUcP!^1A1*h#pYW;OlyId zN%ewM?B#pjdN6!gUfl&?4qB?_D75N)6 zLTej`QrzQnR83QV_k=o*|Gn$O2pj6x9mIznf&Z=tP@)=3{qT&^(C)z7_u#peUyq-+ z9+mYHkg_gOm9+un5e-^pt;f)MRaxuso;tWks0Asb7Vi1I=m9augSY?Oz}MgvHK@+j zAmvpfBdE^n;B4wTJWEh#H&tgh4f~eVxeDG^R)tS2OHgOYg}_{4VCfgb+1QKe%iq59 z(Edl7UMlJ+SPP!B*HX{!7wcyp3>|}rTk|F+z!2$>FM{C0i!fMC5Y9E2AS%~{6GSL? zO6`F!L!HQT_K~gcd@cnt{2Wnuk%smQ_lmj_&iNcZsJ#gSK2DRr$jy%q{4I6uij&oPFsob zCapw|vQRGO-aBUX99BZ`@w+~yU-V0jzVDC8bxQj4?h5}3s{JdzTkSswKkFRSrhM$e8V<|{kOHsWWQ_cc;#95d+ZVqSVXJY7?YU(%x?>PggvMd2f zUSdo+9j`wf8G7zjzX{+%~ID!*!|bWBpq2?b;3#IH0llcmj;?#5tK z{(N{{*?fFtVgi!qL15uL3_J|QjAW^VbGgzeRDhdN!T0oKE92&3idZo>oFY&=+EF{Y z!rFn^RQu$v!HS20%7)KkazIQb2P>)&?HBt(MVG?>y z;(HE#z?Y(DDc`e(pNP^#kkU#(8eM{qiX0#C6EJiF-}5AY3QDJdlr|o(8?U|2lsXRl zipOdEO#E29VJzM{2Bk58z&0ABtkHbW`cnkR}`;FFVu7rkcSGvOpH6X9ool#v16t$aFqrX#^= zD5c@sQ$fl~rEg400eM7<=9xAJhB{~{FXKHj+?{F%sn{O9?m?490xwxIIz(`t;&p#9 zk?zj(+uE$b88%1`mp9w^o>11YylD$a>Th-!zs#t-J>5I^Nayj+Ck$uj5mH5}EFFfA z_sp#&rJH*{x0^dmIt(||k#~g8f+HSh@n!5L{xV5&q%6L)ufA;P?;e>o?;ew6nPXES~1Jxt$fds^c;L49=6Kb_lB>#p=M_4 z&V`jbPd9w>5&<@INL6=LrM;?BJeooHPzEui;2ox`T@W5dfK-?wupOAGFpL9vCdYT*VIUG2d%3X#B8MI(a@jLuOc1)<#CL!3a=tC+?j^FJr?byM&RV^v z&&-n(rrGEA+9m0PT?!hE81F_SWC@{t?WBjs(mT%e!S)x^W|y~pSXlj3=&`n=Jx7+! z{oVUg4{3SxozJ^IEFvAfCiwrdi%aQt$i2OL9o?1JhkC!-XzG3F^)C4X2eDV04nq78 z^6EQ%uNV#*4t~{ou!u}01i}u3cXuC|vOAms_?sL{`wO4Yag+3#tg~(NlExdsfgbZg#aTm7#$B8!LSmc=E$dDhC z@01mJgY1#dm*>k<<X@>ZP_($<| z@p-X}w*LL%h2mLaHat>4bOv+=bOv+=bOv+=bOv+=bOw@`0h=R8CvT%r zLmp9WCBG}LD1ZO``D?Y7z+S^=?c27I(|1|}XJqb~^}K1O2(u-OLKfKvwy5*$SuhmX zC`=$fLz~Q|zIL^<;0JxyQ?4N#|1*wy zKY;LUu!#d+vlqMfzB z&@qE^$rf__?N`lvx^DWM9EBH*qA&Ofz5oneaFRyu1;-USAi!M?m zBxX9tnqshaznqL9|pq`jY1ju0X{v^)armSe;85MVla&; zWriXEpkO1pMpe%js510E3(C;D;N+01_$1R9L~g)vCvr?@intfWGw8CFXk#&yWYF^A`E^;LUd*l!h&GC$2FtgSk@0%-`wPtsgU7 z1xFK?vEaf{dJWFtuShcDv@v^i@@)(CwX0r4SMbVK7I51I#@R~jtk9ENiaxR!87|+O_Eenc&S>L}{(SwUBB0jY(CDd&ZlDCJzR_4}Yh3FC`X7_MN_ z&;F2W>t`jy((D5)VV4PQ-(UgbNRKXKm%(ripZW->*rY;nr=~FrkRh*Fu8%?532(tg{0%%8LOGn;GRAZHg|M9A26T zlVA$;J|%&s_hUm$67+$QU;&fpQ#Cy{{&Jzmjnzu_+LYH%l1meTsnA?VhHRl99L8WO zSV&lbO3W6*Rf#O<&P;+zPB^d9)*|x3`pl}5GjKUr=V|u%+yPIG8k@tI#pZzU5Y#Ye zB(Pd|NCPUyK&Y)k6hH%u)jB6?rXLF}VJU!Y=qDnnjy7MuKcNvD3O(yJA8-54`Z5*0PK3 ze}{Dhad_n4$&>6mrLUw$@ojOj?U%M}n9cD&{9@~)5Ud|M13Cjb13Cjb1OLky0Q<{q zsDZGtztB38zf{}2N>gS595#zk(xyVRRut}z!3In|^bj*`^hHs{cg`ccZ0JE{)jWtJ z&95Z4fWe!;7pVjJp8gSZFnF`z9v$7FsAb}X} z&@GO7AY7`>S}TO z+)bW<$LDHtw;)S-FcF2-UYQY={H5A#N^1$qhM6&}a?)rXuSM728qb3HH>^yes*y^Q zwZ~YHvtcd}E7HPdmO-H5_x4>BcI`I{;-1eX?OW4ML4ng{%GoUk| zGoUk|GoUk|Gw_WWfZ3nH*bP|gTiwldrHdN^|LW~lH@X`eYSel*)Un+lx}l0K!m7DJ z2b-a_SW$Gf1{xXx#|(x;k7KKh8;hp@wfofavTnwOuLP- zoBTIqTZ8ON#;xKQ&VN$bqT^Kh+hm#{N95k*;Hw`S=sLNF;oLu!FWk${?Q?0iB_lU6 zoG7M(iZKMb;>UoH+h9mka1NW9Yy$y|n+QN|NW%T*vHkC`j>rE0*W^n3{nqi;C+vBW zB7P{Yw(Ym&3S0O;^2@(*k+0vNGoUk|GoUk|Gw^T10K@i2;wS*}6pTC!p2DWCGkD(> z`8if`MzLu*YI=ugMKQe1U@OB$b^;_#mvKND28*#vacc9*13SE(| z1a#`;hczrGl@AV16S)^+18yAa$PJIriNxs&hGv~;N{E0`qjD|`Ko3q%7NRsUI0qJi z3+A!}rU5gXAxmoialAz?Y$-gQp`H&649q8saV4h$Hf5st6HrhT1Ox;{7=~n$3?!K_Ga-bQ+`%sPE-2U) z8|sQ{Sz*g>b-(p5th>6dWzAMt*Zu4TgyjF8bEn*y$soAynYiDXALKpv-1gk(yzi;+ zIcMR5Io_bhS>y9JxP#8oCHsM6^~2#N5&1pY^Ub_j5h1CS;|I8{(YBV2uC^?W4R zu14w#d7fG-?T`nFzmXdFE5*C)ZoUdmupeW9F~AsL4E*0_KwBW$^9l+~q0K?}s(Me* z@2>Lr^}q7z=gpkHXr^<~^cizzI`uf`5Wxw*(o*Mir{CA&Z1VV>HQsuU)7x0>t#Svw zjkV5TohNd2bHG!L3p$8{q7Gj;g4~ZoE^js574+1?Bbxl)2DiV}xyI8voLmroThOyU zs7JsHz-s+*k(5-EPJuf@kbeV^IliObf|HQbj zfr!|r%&vh4Rr&nY82u{0yRoXy6BzDvN58Pj2RPRU^{@5&8p?t`XT7(Pd}d?78}#}b zou2ics^*}ly4w#Nj!BFBfIQ>Zz_V834_c|;8Ge_6o!HIY+!?++d~*$eYxG5EjopY} z4L1|ajm-_Kfb!MN4NW+4;12!8L0_snQ{5Z%g+KPB)25rWjD2rhaz-e}DXQPq+~{4~ z?1?7+aA)k!;p8(KeZ!sjBR~TNinhFo*(L;9=~*9GTMzXum%BOWBgZaCd{;UAkuJ`3 z*z-zCOqZ=Cih}8Jt?~u~(EuN(G|}i3s)Ns`)*Eak@k)ZNsJ`Cmt05+X?{?~m1KMn~ znX(8OZa+3Or!RaVAWf^bVX%O~xvJi`Dqh!!#soZIAdnYCE~{y7tiq-ez~4~iTj%k+ zYds^vXZ36$-HHUNQ_kD+W|pK?RwH zoNDm61I_+OMslJ|GIB>OmyFm*_zZkbsoj=0y(rb^gs*dzhXW4H&e`*N^)hL?Mc{l1 z|F_0{1dfTBKte%q^6;D7!8&I$b{q}B2U~417!O6 zzaDH7`(T;~qpTqrQuxyt9O_qZGNvH|Xx9e{Uw15Sb= zxm2o%JtNSHpHaJRFu@clTyQqO2#hXbUl3?$a5q+m%PU+A>raKe9~&orkDiIZjn2Vf zlmRf&gl9$`8a|72tjP06Gyy00sSWOG-Q01a7@pWt=Sg~;UK*X@4tj##29Fb8LckEk zYHC#9RJ0wWCyOwX(c9m-mqaNtvPIrdOqU{K%w5?j=&Bd zn&Xrt;bcr-=0S!FwH>3LVD1cb;6wclICIleaFxzN51B`(mCIgb$(npQBc#Kp{mZH3{6TtWpqehGu;H%8)VWb{bzxZK( zAVbX51B?O2K!gFw(#I6(1uzSiB0k&+V1*0p>f89T z67?JPOZ5}=L-p@!haMHVn@Pq1V}LQh7+?%A1{ed30mcAhfHA-rU<@z@dMpEdwDEwg zNGpQBd72si=6K;x)_nMrIS&40^foKgkX6TmcWP!d4fJfc4aZ-YQsG4z6gf55n4J)c{@56fV@q zOcN`>4wMDmweYFFWcSu5ceel}^bla`rJcrwmQdvn$Z$6TJ>NoM0;K@h2Y8FM zEG{&VDu;L-!9W@2Eet8(ZSdB+K}&oAoV4g#z|~tT<3et#JO*2vJg3HCL@fh=dX4fs zqylimFIO{hAuIiFaJjsV-k{3`sGMpm>Scfw4Q6Ws7s{iGO}BGcozV+x8$zDp^7#Ee zKY%O-RF_4Or7ytN|4SeD?9Ge;#sFi0F~AsL3@`>51B?O20AqkLz!;#wfW>4%GM@i$ zQja0{$9{|f#sFi0F~AsL3@`>51B?O20AqkLz!+c*{1-A{vB*50|8G){;;$>z#ed<4 zvQJ_RFa{U{i~+^~V}LQh7+?%A1{ed30mi`pWd;f~gvbA%6kbNK_TT5~zhLFR_tm%5 z->Cni{#<=geMWs;eNf${-mc!DUZq~FZdTW+KDADDs~4&Z)j8@+b(%U}9jOjg`>920 zjw-7*rAzr*`9%3Z`HS+d@`m!7^0KmDc}{ssc|^HSxl_4CxmLLx<}htg0!qE&QC28R zl=;eRWri|Y8KaacgOm~_U&&Mi#UdY*zmWe|J|uU@e~@37e=Yw){)xO-enNgozFWRS zzER#LUm|ajTjVC$E3cB5$&2K<@+`SRo*4@~H^iS!p(tFaI z(gEoe>8H~3($mtT(*4q1(yh{U(iKv>)FL%X9_b=!p>(!1U78@3NrR+5QjR1_X7Pyl zv3N-QqxgpSs`zv9dGSf{A#ta8i+HtovA9w6i(YZ1xI{cxoGDHbM~kP4eZ_oH6>Y+C z;d9}i!k>jd2nT^;_G1h%1{ed30mcAhfHA-r`2HAhaAw|&o>~df;L7upW2_J){R7L=WnL2han0;C^(!9=H$Prw8su z_v(Rr&^>zKZgjUE*oAiKft_fl9=HqLr3darcj|#1Xonuyj<)N8JJ20^;C6Jo9=HwN zrU!0Cx9Wjg&@Fo4W^}V2xCz~)2W~_+>VX^34SL{ubiE$94qc}Qu0_}Cfosq;df;kw zwI0}pw&{VZ&{cZiN_3?jxB^|F2QEjK>w(MAWqROJbg3S=1YM#BE=CvYfvsq(9tfe3 z9?+1c2ij4)jWhA4wl*TRY$0OvW+FCiB4Xo4A~tLwqP3NX_3MdfX(3|WIwG2zi3kRX z2n2}m`-xb)mWZY%B78m~8XJjdXdt4#o`^MTh*-Uv2(Oojx;i3iYl*0-A;RM!qPm)h zswyH@ts=thCSv7EB3v#aR;(am`EnvIx`>En%ZRw}LLx4>fQY3_iCD6Pi1W`UV)0@k z7A+!T;X)$LJCBG33y7FMpNM($h&cCLBIeE|V$K{Q&N+vOv(F}C_G}`~I*W)i&m>~j zEFxykB;t%Sh&cUpB4*4WV)}FC1T1HA|_8JV$vicCQc+`!UQ75 zk0)Z>I3mW5C1T7NB1VrUV$>)i%FBruIg*I7G9pHdAfmLCh~dMD7&eTE(@rB|=ujet z3?X9hU?K($B4Xe`A_fc~qJMuP`t>8CZ(kyuP9jQ5h$t>5qE8o1W1<9?_M<^g&ApSpb zqVT9t$lt_E4$c0deYx#dwqe#AtvuIkIb>OEe$L#_bc^Y`e3T}_E{s%n-y}Pj#($c4sJ-OJOk4{kCnWBP5-GPqFx9)k^1u~n0}P*Hjj#WoFIkN4jloPIRMG;_gB z#87tHF+p0b&~mv@S(=d4yYZ&ht~!sqy58Fux7G7>w_({FM*b*ekoASEYh zGVIlzCdR^roFUJgsAWT0*8|`f(=AKmp{PqgC`hhM&Ble)G(j=!U!9?GT!>FgiR*$5 z=^>v6GSJhw5bH}HMXZ_@XkHbl@_U=`zS$Vjb7`+Q27Jx_Di5hR{+RwA@(H!r_>JT- zLC>bC+Gt2JQZd31I))`NQ^u&C$EAE`x|G^r<7lsDGOvpO1+IiPp#jLbHq|yQ45p>s@DX{np&Yj+gRG@X$e%hgH?4Ne>kel z5QXdC`a8=E>|0g|7JO+&Q@-R zmH0-OZ?c?W`m<^9cWL;4+dWzV7aC39B=okpp|Bx!CSxT9?bar8p#W8A4ZdnmeOWaW z$PrBqxEg$ZkE`Ch#^Vasc>~cCu5eKhxzOeI2fbDGdO;P^Msgwd4+T2Tq%~~>7jjXx z$5SCYOfF`>xgOhZn>LOM`Fbqg8n?IJQ=OkX~Pp^a&0pd5ddg3u8R#z1E8w<=0MQn_cqqX zKt)U43S3*wOCPF;hT-b`bo$jGJf4BDbAB)5t z6oaW2RisVTeFebpZUGk1lbV?e+0&q=hDutVW`Q07su(=$t30IT9dNC3lUlNkdM!DI z0TP0vZ=zMC7T&Daw*i7(x)d$@4=H~dzK*m%Tvd=o`x@Zukp+e%iR+915+a*=f?9C7zsmM9dP`G_}$q0Pgx> z0LOTT7XsepJrr+JTU;Ac0B{?6DBP50sLA;NyM#XM6iryolm~e1^zj%fy_zi-Fl5ri z;P;Rwvul;72KThp`Fv}z2{?KIkX|%_#6~f~2?SlixFxU2Ikfd88HzEDOxd*cM8{*q zkd*}(hSE%)SgSE&Ke%(<*ki0YGHL5fx1g}jSTg{MnjU_P>4a3kVWp140AZ8DA#F2F z1i{uOkE=Q8t;Y$0WZDGiEv#4@uT=s9T4)jwZR2S+5x$;kcD~MC@2w_-Wv&KK&<#O1 zB*O*)IB2EGK>$YN8r-DzC-6W*0nL{ulxfZW`e?akbpRNu8AAk&y9T<2qd1VAx?Lpn z>}X~iK%hDX8|&PPbg;Eq0fU96Zs1bO(Br$A1IuWm2_QxS7-owFULTEH!H#_k<%9Bc=_>I(afGmr|2x0T@v38{{YiU2 z+qKqX)*0M&miH`u%{QAlQvm%1ZtDK0$>TtgsWxVCF^8pY4X@K;z=G@(UdWO zr!UO}*ZVFamDR+N9!(jYPC&7-!Dx!{qX1AIO@@-2IhZ9}YnxaOSg6*Snp&&fjo`tN z;Qf)P-}*>ujJ@!&!TCcQITEmYsPg#lV8?Wql>y|co(nm-%W3=wKuopVIyD7J-RqQ5 z3djehh3iOOl;As|WeiUnBtvt-KP7D$Lk{fX7Eu zVF)$x?v&r5Kpj2+a8n%(`Odg;vJdMIaF_K=nv)CC(ft7Jnx2U^bs;MC1=LiF2ci zeziQDXBbtj?JPh-wa1@mnj!bfIuj639XmH7NRe~(ngyWBsOwIW(j?|uMKb}{WSY42 zdPEYiZnLedGiWE}x1hteR(3joqS~9MgZl0nSHTQGOtsk55uZ%X#ZL!pX{g9{lXYpR z60lHhXXrc`GOz3kfG~`{J%%Bq$h~r>0V=8$!W4Fxn0;kV1z=R`HL*dJ#4If0&z3ud zHd!aYWNgD0O$K08^ZJlX;K*&6Bx`UBejYo`Ie* z?I>|#RLb7xs-7_;EfH_xvB4*yMjOn97NmWmR3gHJV<^x(^p{IZQIU%@_W;xx^q09y z2`W;AEYb2|-Ig?@Xi_~XvA|ub<#D0%o`5W&EYtMH2ix-CZ@iutt-F{cKud2C0UvLby<9xA<>csjmnD~X06Z30y9bRm@ zGz}ScxcHAOG@X!LZ>GOEa2#JTJM*V&t)nnOi76JKzr<}EGYJW`O3Q?mx6`25Nh`BO zGsf%bFPp40lvF#4R3nWeP&4uPe*twdzuq1tIT^~<^KTO(&K*G059~f%%#~OOh&Wf2OAPv5)rm>X`rtcrwy+I znCW&RON5!SiK&UT0Jn%bt6_i%7Os`m0GhOqC?&F&cx-6!YJ)t0cmYlR^bFv{YMFo- z>L}X4Y5+Q~rvXj&6D+L)oUWdRGqnLps{k+6p79fvk(%8NaI$IA7aMcYwJtLHBdw%O zOcD~~m`|n);7}bPi;ZA}%@Ge^#H}M>UqL&uy2FHXhhED8301F*7?PyA4CX03&{KF3 z;G*hF79HqGf|Xc3)^e5sxKgUN7MXyR1TNN!&~h&XSX9TTyLWL*;w$3<07i92Qun|N zT;(kVNTX>cVT$^D5?Pr`02$T%Dg`nFTUqA=CaMl)u`E4NsE9T0oyfZ?+~a0C-eu zgVD6^#*a%-PKWjXXCV8%_B`|!ngQzoyeGdX50P$`OyWl2Lt!C*x8smwjBT0q0r3AH zXVJ_*H|Lu?vBp3BjXq))Z|oX3?rMM@q2JwVK&5w&N3tJupH|L=JXCu%qe&ibMhT5R zSIRa^gEo{4E$)eslbVB#+7vF-O0~}~1-nU|fZsktA6=u3=0deUAoNfypsTe>T&TGx zgHEZ~=t^xA7-LVyo}}UEDy$^lo?wlqP!2D|NhpZd>5m*H7a!2`iH+?J z`m10kV=;7-pxb*)advVE3nY%zCcyqZJ;8udKu(!ojiB$~b!t|Wlv|b2ce;rpKA~s+ zJo;mmiNGSQ6}%SU0=&(mm>!*sO`@1j-=Qo@N-96;33wEDV0xH|U`iNvDos00$*$Yu zv0s#&9-0j0!BA)l-VtjK_M{Mfk1a#VY1mLM+7jH8*0S7)C|tRC6#M@dp%$c`qdcnQ z%bTS4rL)96qAIlVhxkQ~mmS0H*V&P6t@Ul|Iow`uxaCfZ0KWf6O!eq9)B^hnf47=6 zYp>?FO&`Ggy$?!B*SP~(D{tlzRd2Y0-5buh6Fa3?eqDYKgj?rFdU*B^ zWryE!AJ-VDWQW`bu`A`Ubi#?UWAw?rC+#dnVc|r(8~aoCNfS%mc;;@ye)wb4gy&nF zb8n)*KW|LI%)bnrYA8^VqpKg9y3UjILe!N9PYBk`AL)R|Gyon zOO*$eUh*pGSxFSn7k({F=bz;JIc|4I_Ey_JZ5LR7VjaZYWI1k`3G4qmOy{HR|M89< zZ9HtfOL=AO?mVZHii>X_*40M9ey)@kZ2LE$gCc0Wh5&II78i=lxiU;p(@NU_OWHlW zQzd-TkcT#Q3*hz9bU8Ye)J{3Lq~&Y|+*I9Db==_`DU$RFg^#9g0$BZN(rM_ojcaK{ zJk@hH(k3b;B16}^R^_5SkPOAXFVT zjX;tTNe%#f6 z9qI$nOK4hL)cjBErkd~(I4>X42v`^QK&;7?!;uXD)zbr^rmh#N^#GY}1uW7z7f$QM zD&dGVfXGdgM3M=gl3p6Ud$fV80Wj6cw5JXj3`sC8M0x0CB+r$8A`P@Z=%^I07d|%+ zwHH|4v7Bdq!E`-(*>;Wf8}0+uXKfa|{M-CRj^F;r+y1Be0{Z@%dKul#5YDCCYBcRs z@yD*m9lWJf2Y`&VjYx|uvDSfZr0+{Za3!_DBh@l=1N{Nc?wCr*sL)pWjul2&vFcDW zeeVGykVFj%%7;;VOwH+sG@c7(r@^q2hvpx^o}WB@DDh4dyXdc#qw5DDBsvOjbPm{= z)-;Mjf?^TfrAgq;L3OafXgvwJN-ce#YJw(dXf4sIFQh-#-94~azIOrr4A|f-W!Pw5 z+{|g4scVp{Iq0ni4OY^W{TsM2?xHyan|3eiY?LL!0cHl%9~4fdv&mcb&ZR%_dSY-u z*c|#!2i;>z$Q5VNUks1nN;N<|2s=oPrLW^BF*toTLZ-{;*SXjm6BwZH|4%eFrPJ!; zc>KTJBq8-n<%n`n*{keUwkwO3vy}?jDt#^;lHQeGm;Oiksq~!mxOBgCr}&BZckz$n zYvPmQa&d+@Ml2Bp;cMYz;qSuR!Yjgy!c)S7!VcjE;Yy)R2nwr(mBJ!nhA>VT&Ogih zco)BzpTU>$1NlNei?=(v92Ys}I7%J)4#EB}`yKW+`&xUgeVKi}eU^QaeTcocJwLW6K*Ls`vI_?0skGqGP$Bp3zalN?= zOQ+>i%VEnOEw5YlTYhBOZ5e8Q%lwM@CG&3cE#_@z&D?5kG}o9OGu>%wH}wYs;FkkK z;AVaZYIk(FF8KP$&Sx9MclI7GS=MGX@!GgH5?j%A;FYEJ56~`qe!)L0`=HPFckR6X zN#%E@N_FI@H?>LVu(s_1%ki$Ru0#78-q{=dcS$q^fthf+OU18r6m8*5{Ddv|*%R7k z{Z{MrzO%Qq9$#WdW@R&+EZ&Sy9)>qc+PF;sB~-u3(eY8+Gs|E5dgoeu@8d83*m6zh zHx*UC+*Z(4fuGz~zVD-NUP|@vZ##DG_$+XDC%!WJbG>iDaE!l$6)W-SwyvWUZClV; zuj7NS$OXIfc=)^TVH|Xk*n>Doel1DY+BU+6C>wY28$jl4;F?DCv9;o;);fMYj#}?n zIl|;H*)xS$$VGmv&RqF+XrBk=-Nn5wiE6@!Vx-wU1k#h zIgTN}w!ul4tBxl8txb-OY{3ViT%V(3&En>aMhN$7j4?GyXuxM1$XQ1{zNa1-b*#am zHI5EmSdGuGc62hRe*IJ!*XU88lAFwOeqr1^F<_2XpY0R`(c zavov zya1oPz+f^qWhq1zFO3p5c?le^UqX(%^gM)M`-9OEAa!GwkxRY>UsMt}AE$QB`6sf8 zqf^OOhyU#AYCrnvzJEoi(yfK$9N)kL-~SzcEHMU>^!SKyWVp`aSd2e!F}8z65XxPo z+rdHz_gfg_VUlnjK6{>S2Mh2$3*a7pK7?}SLu|7+4}$sg@C9#}9OvRI&c&887l-Cz zOPK?q+&Q|XoCD#0=NK*JY<%`?-BM=bduGEu{8{Y+ z-Mik|yQkqdCGCAGAaY6ti9B$iZqmW7BcK<{-onP;h1!*AaJqOJKCK(0b1F8*%Bf*v z>?#;t^Xk`KJ8`n+eYW}iue$wLdg$0+ckC3uz*j|nPkdxDY7vCnJ55+)jCN;Gl9N^@ z+Z2GTOxeXx2AMONnA;>AHK~rDh@&PFbDIFctO<^eWw3)2Sk(BKn(ek^j>A#o3`S;h zjK$ZFb##;}V<1#KMyCWy@L8jAqDrH2#DuN_Tq13o+;Ldz0%mUegnaIg47Rp6E<22s zM-_ol#PUYbwY+ltS>@RBMnWieq;7d-5bjqNqhyjW0-qhBTV5%?rxd7j49B72*an9| zC}$Y9LH;xxJPm?&+fWE9L(PsM__`t3mImXKgRw2~gK%&V1ZBrSe10Id&jAq19e@pN zTtx=K{3khO#LP&9%GfMFFB{&^k`LU(F_@I_u3^7BB zam?30+8NgP>^?ZM4~`si?>{P^zNGXhGD*E5vamOf#3oz>M`Mb}eF>%Ed4)KY1{9KW zCsA|6>3{55L;B|$Gv0gfX-iQ7ylz4Peq^!@EBSD;I3J%R6-HYg94mQdJ{M$8uA`$f zPaE0`8|8Vu!bXX8unp_rzOW8{25&h*4YIqU@r$@T9$RX-^7z#gU7tlNKYHB}SE<_I zf7f;#(rb>90!6R&7_PJBVE8$^?AahQvYl;w7XFSbVy2n+TxOj;1E0%qw%Jr1p_&~E z$SlP?B%7BZlp}Ko4_ieEg835nao2CYva2E-IK^xJVL|(ME@^48hsF!Q$;FL=qoXVL zNa5JiQRYkA%wOkJZqN2j`)udYozI!hEktM~T4`%HeY9&@4MHDEA0K+Vwf)88U3sXz zEf4*&vtn~QLK*nujlcG;F8q0;Bf%6o>O5o=9o)k|B~*L2?a)XIX7Yd$UKc^*^D zgJM~E2M#)L@C-ZFdxzc8@!4ku_@($KRM!0Y?)(9_pL_9u%C+cplNeNsoENwC6Uu60Z2u_LB@4#J~2$NoD_ z@YzEyHn#(H?FaJPO@l3PX1>L-|Et%Fg#3GEE2fT}ohCGA>8?(z10AzWS#(^Mq+_zA zZ7>7KtwA&BMAsK8YTNoK-#PW1k9WNAUe&g*_I-Ix@utpS)gIYl>W!3d-hoQI1?_1A z{!6-UMdq)6diTDPFHHG|KiSvze&epTH;(>(`f<}PQynVY1r4e8qwlm$LX*&jeacZw zyA4$yH=#c8Rd1CbTM(Y1Htm1+0^hT?{q1luDsJcCBaq$(=xA@`Msn@P^Wh zqgOxjgz0jG6gUZ|mHnmuwqFj6isee&_tG=v0r{1sLs$QXPR@bUk z>bdH4b+kHId04qsIa4WD1}X)LMgCI$P<~&2L%vboD6f%c%ai3Yxu4ui=A~ocL-4S) zL%LQ9N$aIGl3N-sWlL7^EAeOW3ie|RFa{U{i~+^~V}LQh7+?%A2EGde0<6Gk=5x@K zxN~Y0tPpADtI;04LI3NC6%!8~nz7v2V|Lv1McWn_!@0p8yk9tY=U+{IM6C>N%0*A$ zZW~2}U61k6D;JY z_Ezrkwkg^Gh+B{DOY8>wz47Z2I&S~ntz8XWM@-Jy8`06m56lPO#{og>Po94-ei@8f zz(E$e2X}92eaVTt9Ubp{AZSi-nnV*L4 z#Q28vuj=y<^eU~ae$>*84q6CY8Fqp*^Mz;!z5+UqdVwE`nLiC}$H!mSfB7!-_FdJ9 zqzYIUz|3z!cjz=vbG`aiq))VMGZ{6E=*;1gJ&_)kf0+)y@UU3fHW&gHJ2)a>a&HID z^C6UjZqqr>Bhj}4=eZ>M7R-4zIMSN=LFndK7vApO79JMpz+ZY3blvf=-VzSq2pwqI z;Glx9zQNGpx!W{X%e0z#EgxNvKW4%KGBP=JKa5Nke{C35i0j)V9mlb8g}t%v&8`X+ z+>OnAF}e;vj&x;h)KvV2Ai6d&v7uKb_Io0JAoHmDP+8YIou64MZ@`0YdKWPw9ZtB9 zI6N>zn%?@T9FE*~W8$^IhC&#)2DC#2&nlemSCbA-0UQM}!`pzp53*n#8Z$otU4>8S zzc)-GIH%+5uO!#=;0T4eyn^uRAmPi2HrdHlmyzyF5mrUR_go4V`HU$OR(iy`e+fRf zn>_ao5u8Zz6&I5ZPF}OXQ5M>{4w24I5OW@1`DP<%P$#=ai(z=WF(X~b}>wz4f{~z*|TwT zj2++?OIdxoMTONT8}d{X8b))9k^xKHtaTSADm=|N3vzeL2^XE!mvZukmJg*13XP>n zRuoluhFPkqE?N$hc9d5|(4Dm6(=gH1T2r9pMWMblIU~4Ir=kkp-<0PG>bZAnNWGxq zKzS>rxar6#wJHN#|7g$mcL(bNWjHU0SNZ5Hoe)ZBv;KK0D%JgELt z-cB%<{_zD&f;YW3PICaXwKQoZ<;%aH6O_V~AIj@ReRt$~Q^N*;sV-HaS22?3D{I4{ zahd+@$WPw-$3Vjug&KOOnx?k=Y-plWZXf7renP7kq$McJT#Uq*#RVtD&zww7jR`Oqq$*K_`4@Zcl@oR73Q_=tju(1JPU1 z0(6-+jte#PRKO|K0bL9ON1^3C6?c+epi8h~xYMn_NwexB8A4(FuPZzdh6+Q=dMNHBz37kk6B$Y$?FqN5J2Oo)=DXP>dNxdq3|Z2~ z59rfbX`1RC*$ytTGj?p6R#%ANNoc$GO)EXIdQD_;Ch*xdpFypb%3kze$v}^&8lPOz z2RYOLZ44J$LqCs8AsC{+E_qBwg1n6BsL<1S+RiPqL4_lKP`&I74+e;Y7D~++h?E@1&ahpm(V;*A ze?!W{&<3M6fQk-dWe}RocEXu`zlBO=ZTyA`kp#DGwQv3>tFAZgPP*|0@~1cqyk~YG^nG zC2%IDJiKlIWN=dpdtZs*&rEsGiCESYhU51{nq`_Dy2U9k)~{zu$xs~7l}xz`Wc2(D zKxQ4K1?K1j7OHz688RZBn`mif1Fv+-wbZD}#H|nu9*z9~3005AD3SnSC0e2yR*BU_ z@Xk-KO+{hp6;~&~p;~bzHWi;%DojkE?22cw>?k3|bh5+zi1cMPQAjwAEHF8PavMj_ zY~m9s17?6wZWJ5yyeK7xR1%>5uG;TGYLopQ<yK!39cQfCMl`ykMZc>5R18_36cM&f$%!&BrorD4bM zREP|{H5=)V+8dgZgs4bMaxM6Chq9@TNF_nhJJ#IvN6V9t7}97ZeRq!-oJ8lJNNSx= zf8qZVfYQ@#D*bIoPJqdff>ZE*UwLU#?XV9A-t{jwUbO$HQHJy(doQ&O`Z vkFsZJlK{+6>h7vBFo~UO7?q+;1XO*~h|1_mixKfKtvbDlrhC`miF*GZH4iBS diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/api_client.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/api_client.py index 6fba226ab..538ca03a5 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,49 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from newscatcherapi_client.pydantic.author_search_request import AuthorSearchRequest +from newscatcherapi_client.pydantic.authors_get_response import AuthorsGetResponse +from newscatcherapi_client.pydantic.authors_post_response import AuthorsPostResponse +from newscatcherapi_client.pydantic.cluster import Cluster +from newscatcherapi_client.pydantic.cluster_articles import ClusterArticles +from newscatcherapi_client.pydantic.clustering_search_response import ClusteringSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_article_result import DtoResponsesAuthorSearchResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_author_search_response_failed_search_response import DtoResponsesAuthorSearchResponseFailedSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_search_response import DtoResponsesAuthorSearchResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_author_search_response_search_response_articles import DtoResponsesAuthorSearchResponseSearchResponseArticles +from newscatcherapi_client.pydantic.dto_responses_latest_headlines_response_article_result import DtoResponsesLatestHeadlinesResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_article_result import DtoResponsesMoreLikeThisResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_failed_search_response import DtoResponsesMoreLikeThisResponseFailedSearchResponse +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_search_response import DtoResponsesMoreLikeThisResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_more_like_this_response_search_response_articles import DtoResponsesMoreLikeThisResponseSearchResponseArticles +from newscatcherapi_client.pydantic.dto_responses_search_response_article_result import DtoResponsesSearchResponseArticleResult +from newscatcherapi_client.pydantic.dto_responses_search_response_failed_search_response import DtoResponsesSearchResponseFailedSearchResponse +from newscatcherapi_client.pydantic.dto_responses_search_response_search_response import DtoResponsesSearchResponseSearchResponse +from newscatcherapi_client.pydantic.dto_responses_search_response_search_response_articles import DtoResponsesSearchResponseSearchResponseArticles +from newscatcherapi_client.pydantic.failed_latest_headlines_response import FailedLatestHeadlinesResponse +from newscatcherapi_client.pydantic.http_validation_error import HTTPValidationError +from newscatcherapi_client.pydantic.latest_headlines_get_response import LatestHeadlinesGetResponse +from newscatcherapi_client.pydantic.latest_headlines_post_response import LatestHeadlinesPostResponse +from newscatcherapi_client.pydantic.latest_headlines_request import LatestHeadlinesRequest +from newscatcherapi_client.pydantic.latest_headlines_response import LatestHeadlinesResponse +from newscatcherapi_client.pydantic.latest_headlines_response_articles import LatestHeadlinesResponseArticles +from newscatcherapi_client.pydantic.more_like_this_request import MoreLikeThisRequest +from newscatcherapi_client.pydantic.search_get_response import SearchGetResponse +from newscatcherapi_client.pydantic.search_post_response import SearchPostResponse +from newscatcherapi_client.pydantic.search_request import SearchRequest +from newscatcherapi_client.pydantic.search_similar_get_response import SearchSimilarGetResponse +from newscatcherapi_client.pydantic.search_similar_post_response import SearchSimilarPostResponse +from newscatcherapi_client.pydantic.similar_document import SimilarDocument +from newscatcherapi_client.pydantic.source_response import SourceResponse +from newscatcherapi_client.pydantic.source_response_sources import SourceResponseSources +from newscatcherapi_client.pydantic.sources_request import SourcesRequest +from newscatcherapi_client.pydantic.subscription_response import SubscriptionResponse +from newscatcherapi_client.pydantic.user_input import UserInput +from newscatcherapi_client.pydantic.validation_error import ValidationError +from newscatcherapi_client.pydantic.validation_error_loc import ValidationErrorLoc + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +138,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +164,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +181,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/configuration.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/configuration.py index c5694211a..512b78e0f 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/configuration.py @@ -139,6 +139,8 @@ def __init__(self, host=None, else: raise ClientConfigurationError('API Key "apiKey" is required') if x_api_token: + if type(x_api_token) is not str: + raise ClientConfigurationError("x_api_token must be a string") self.api_key['apiKey'] = x_api_token elif api_key is None: raise ClientConfigurationError('API Key "apiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/exceptions.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/exceptions.py index 4c56077b0..be82aa128 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.py index f23f5453c..2c2f04767 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.py @@ -981,6 +981,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, sources=sources, @@ -1301,6 +1302,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, sources=sources, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.pyi index d1c9d6f6f..69784c2bc 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/get.pyi @@ -960,6 +960,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, sources=sources, @@ -1280,6 +1281,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( author_name=author_name, sources=sources, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.py index 3be687499..62d2544e9 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.py @@ -544,6 +544,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, sources=sources, @@ -864,6 +865,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, sources=sources, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.pyi index 613e0e347..c04629a05 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_authors/post.pyi @@ -535,6 +535,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, sources=sources, @@ -855,6 +856,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles by author. You need to specify the author name. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( author_name=author_name, sources=sources, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.py index fbc6d41f7..5ac9b4dc4 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.py @@ -904,6 +904,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, @@ -1224,6 +1225,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi index 3a44b7a44..e80f833e5 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/get.pyi @@ -883,6 +883,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, @@ -1203,6 +1204,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._get_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.py index 4990ab679..6864c2f9e 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.py @@ -544,6 +544,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, @@ -864,6 +865,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi index 7286d27c5..4ecedfbf5 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_latest_headlines/post.pyi @@ -535,6 +535,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, @@ -855,6 +856,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get latest headlines. You need to specify since when you want to get the latest headlines. You can also filter by language, country, source, and more. """ args = self._post_mapped_args( when=when, by_parse_date=by_parse_date, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.py index f034dff4f..25010965e 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.py @@ -1093,6 +1093,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1469,6 +1470,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.pyi index 3496cd492..d7e4edfb5 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/get.pyi @@ -1072,6 +1072,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1448,6 +1449,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.py index b602b4909..8b6a9db05 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.py @@ -586,6 +586,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -962,6 +963,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.pyi index 6d94f7869..7777b7b25 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search/post.pyi @@ -577,6 +577,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -953,6 +954,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to search for articles. You can search for articles by keyword, language, country, source, and more. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.py index 2540c1865..fdc7f1e3a 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.py @@ -1053,6 +1053,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1405,6 +1406,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.pyi index 743758a76..e928e2443 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/get.pyi @@ -1029,6 +1029,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, @@ -1381,6 +1382,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._get_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.py index d0530592e..1c1b1c742 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.py @@ -568,6 +568,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -920,6 +921,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.pyi index 6bcdb585e..0991513c7 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_search_similar/post.pyi @@ -559,6 +559,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, @@ -911,6 +912,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint returns a list of articles that are similar to the query provided. You also have the option to get similar articles for the results of a search. """ args = self._post_mapped_args( q=q, search_in=search_in, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.py index 8f55cadca..f1fcd1083 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.py @@ -376,6 +376,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, @@ -448,6 +449,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.pyi index a9038a65d..97326f821 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/get.pyi @@ -367,6 +367,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, @@ -439,6 +440,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._get_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.py index bde275aa3..a2a8db469 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.py @@ -358,6 +358,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, @@ -430,6 +431,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.pyi index f3f3ac07b..4581eb23f 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_sources/post.pyi @@ -349,6 +349,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, @@ -421,6 +422,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get the list of sources that are available in the database. You can filter the sources by language and country. The maximum number of sources displayed is set according to your plan. You can find the list of plans and their features here: https://newscatcherapi.com/news-api#news-api-pricing """ args = self._post_mapped_args( lang=lang, countries=countries, diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.py index 491d179de..f23220ef9 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.py @@ -293,6 +293,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( @@ -347,6 +348,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.pyi index 43e448df4..f9f81862f 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/get.pyi @@ -284,6 +284,7 @@ class GetRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( @@ -338,6 +339,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._get_mapped_args( ) return self._get_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.py index 188d5198d..b70c6d5fb 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.py @@ -293,6 +293,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( @@ -347,6 +348,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.pyi b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.pyi index dc482c91f..56bb14970 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/paths/api_subscription/post.pyi @@ -284,6 +284,7 @@ class PostRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( @@ -338,6 +339,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ This endpoint allows you to get info about your subscription plan. """ args = self._post_mapped_args( ) return self._post_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/schemas.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/schemas.py index 7ef6c3ce0..0d7920fe2 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/author_search_request.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/author_search_request.py index 4b823f576..999ba62f8 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/author_search_request.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/author_search_request.py @@ -19,6 +19,7 @@ class RequiredAuthorSearchRequest(TypedDict): author_name: str + class OptionalAuthorSearchRequest(TypedDict, total=False): sources: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/clustering_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/clustering_search_response.py index 7e5d656ef..269f5472c 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/clustering_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/clustering_search_response.py @@ -32,6 +32,7 @@ class RequiredClusteringSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalClusteringSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_article_result.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_article_result.py index aaedf1377..91bf96588 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_article_result.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_article_result.py @@ -35,6 +35,7 @@ class RequiredDtoResponsesAuthorSearchResponseArticleResult(TypedDict): score: typing.Union[int, float] + class OptionalDtoResponsesAuthorSearchResponseArticleResult(TypedDict, total=False): description: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_failed_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_failed_search_response.py index 9b2fc0223..82f894f98 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_failed_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_failed_search_response.py @@ -20,6 +20,7 @@ class RequiredDtoResponsesAuthorSearchResponseFailedSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesAuthorSearchResponseFailedSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_search_response.py index 0a6804cad..f29a1413a 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_author_search_response_search_response.py @@ -30,6 +30,7 @@ class RequiredDtoResponsesAuthorSearchResponseSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesAuthorSearchResponseSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_latest_headlines_response_article_result.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_latest_headlines_response_article_result.py index 3ff01435c..a1ea47e3a 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_latest_headlines_response_article_result.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_latest_headlines_response_article_result.py @@ -33,6 +33,7 @@ class RequiredDtoResponsesLatestHeadlinesResponseArticleResult(TypedDict): score: typing.Union[int, float] + class OptionalDtoResponsesLatestHeadlinesResponseArticleResult(TypedDict, total=False): description: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_article_result.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_article_result.py index 197888ac7..ae56eb52f 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_article_result.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_article_result.py @@ -36,6 +36,7 @@ class RequiredDtoResponsesMoreLikeThisResponseArticleResult(TypedDict): score: typing.Union[int, float] + class OptionalDtoResponsesMoreLikeThisResponseArticleResult(TypedDict, total=False): description: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_failed_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_failed_search_response.py index c4ac68e12..8700463ca 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_failed_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_failed_search_response.py @@ -20,6 +20,7 @@ class RequiredDtoResponsesMoreLikeThisResponseFailedSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesMoreLikeThisResponseFailedSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_search_response.py index 5487fe83b..97faed9a0 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_more_like_this_response_search_response.py @@ -30,6 +30,7 @@ class RequiredDtoResponsesMoreLikeThisResponseSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesMoreLikeThisResponseSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_article_result.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_article_result.py index 32ad12dba..31162354f 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_article_result.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_article_result.py @@ -33,6 +33,7 @@ class RequiredDtoResponsesSearchResponseArticleResult(TypedDict): score: typing.Union[int, float] + class OptionalDtoResponsesSearchResponseArticleResult(TypedDict, total=False): description: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_failed_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_failed_search_response.py index 87b5836e4..bb02f34d6 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_failed_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_failed_search_response.py @@ -20,6 +20,7 @@ class RequiredDtoResponsesSearchResponseFailedSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesSearchResponseFailedSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_search_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_search_response.py index 1b92e7cc3..cd65eeb41 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_search_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/dto_responses_search_response_search_response.py @@ -30,6 +30,7 @@ class RequiredDtoResponsesSearchResponseSearchResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalDtoResponsesSearchResponseSearchResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/failed_latest_headlines_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/failed_latest_headlines_response.py index d381a3382..13739c66b 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/failed_latest_headlines_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/failed_latest_headlines_response.py @@ -20,6 +20,7 @@ class RequiredFailedLatestHeadlinesResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalFailedLatestHeadlinesResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/latest_headlines_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/latest_headlines_response.py index e3341a8ce..161161e89 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/latest_headlines_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/latest_headlines_response.py @@ -30,6 +30,7 @@ class RequiredLatestHeadlinesResponse(TypedDict): user_input: typing.Dict[str, typing.Union[bool, date, datetime, dict, float, int, list, str, None]] + class OptionalLatestHeadlinesResponse(TypedDict, total=False): status: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/more_like_this_request.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/more_like_this_request.py index 4a48faff9..197a4573a 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/more_like_this_request.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/more_like_this_request.py @@ -19,6 +19,7 @@ class RequiredMoreLikeThisRequest(TypedDict): q: str + class OptionalMoreLikeThisRequest(TypedDict, total=False): search_in: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/search_request.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/search_request.py index 91db82dae..ba631ccd7 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/search_request.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/search_request.py @@ -19,6 +19,7 @@ class RequiredSearchRequest(TypedDict): q: str + class OptionalSearchRequest(TypedDict, total=False): search_in: str diff --git a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/subscription_response.py b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/subscription_response.py index 38df50ee0..049eafe9d 100644 --- a/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/subscription_response.py +++ b/generator/konfig-integration-tests/sdks/python-newscatcher/python/newscatcherapi_client/type/subscription_response.py @@ -21,6 +21,7 @@ class RequiredSubscriptionResponse(TypedDict): plan_name: str + class OptionalSubscriptionResponse(TypedDict, total=False): calls_per_seconds: int diff --git a/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/exceptions.py b/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/exceptions.py index 4d305033f..d995d7d20 100644 --- a/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/schemas.py b/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/schemas.py index ba01d9bf7..05bbb8fa1 100644 --- a/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-one-of-uuid-string-integer-path-parameter/python/python_one_of_uuid_string_integer_path_parameter/schemas.py @@ -1878,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1913,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/api_client.py index 745403f72..f6d40a8a5 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_additional_properties_anyof.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/configuration.py index 5c9448fcc..6b452acda 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/exceptions.py index c6f5c0ce0..2bbb9ddcc 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.py index fbb45cdb1..42d4a4500 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.pyi index 796e5b7ac..69291593d 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/schemas.py index fecc25f38..d4ef81d48 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-additional-properties-anyof/python/python_pydantic_additional_properties_anyof/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/api_client.py index ed3279208..39b25fb3c 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_any_schema_dict_response.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/configuration.py index aa8008fa5..edfdfb105 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/exceptions.py index 91dddf491..7631a5ecd 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.py index dc09c0a87..d08037062 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.pyi index f39141464..6eeed6b7e 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/schemas.py index 2266338d6..cd36695b7 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-any-schema-dict-response/python/python_pydantic_any_schema_dict_response/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/api_client.py index 64cdc7837..ac5c33f83 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_array_with_object.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/configuration.py index f4e46a490..35d99b2b3 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/exceptions.py index bca13f9e7..476020911 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.py index cae0d5ce1..2445df68d 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.pyi index 1453d6aa1..d2aeceb05 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/schemas.py index 665648adf..05a0d7cb7 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-array-with-object/python/python_pydantic_array_with_object/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/api_client.py index 405c1e1da..6c7f9bae2 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/configuration.py index 795beab8f..bbdd4c484 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/exceptions.py index 4e28290d6..acf7059bf 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.py index b3c6e3dfd..c53f8ec7b 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.py @@ -247,6 +247,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -295,6 +296,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.pyi index 74042da82..c68ed2047 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/paths/simple_endpoint/get.pyi @@ -239,6 +239,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -287,6 +288,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/schemas.py index 51536b30c..e3c7ba974 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-empty-response/python/python_pydantic_empty_response/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/api_client.py index ff91aa68e..437e3a2a3 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_enum_str.pydantic.enum import Enum +from python_pydantic_enum_str.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/configuration.py index dabaaabe0..2367af2d1 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/exceptions.py index 92e239302..c1d2360f1 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.py index 525a2a31f..69837afbe 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.pyi index 8a45d7430..dd0570171 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/schemas.py index 0b83bb38c..f6c045eef 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-enum-str/python/python_pydantic_enum_str/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/api_client.py index 5314ba523..6f02e2aec 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_free_form_object_property.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/configuration.py index 900bd8e15..fc99ee69d 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/exceptions.py index b26b805e6..3a026e06d 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.py index b723475ec..bbcb506b7 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.pyi index 5bd0db8f0..2556c5785 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/schemas.py index 5b7c28015..454316d85 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-property/python/python_pydantic_free_form_object_property/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/api_client.py index bfee8fce9..15211ea87 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/configuration.py index 92c0514fe..2bb1c9530 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/exceptions.py index 3440fe189..6272c4975 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.py index ff0d4f096..b0f7f3d9e 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.py @@ -333,6 +333,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -397,6 +398,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.pyi index 8d905a9f1..6aa9cdee9 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/paths/simple_endpoint/get.pyi @@ -325,6 +325,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -389,6 +390,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/schemas.py index e98884923..8cf44aeec 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-free-form-object-response/python/python_pydantic_free_form_object_response/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/api_client.py index a417e20dc..1ee692692 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_list_in_union.pydantic.obj import Obj +from python_pydantic_list_in_union.pydantic.response import Response + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/configuration.py index 802b66b5d..c575f4b00 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/exceptions.py index 25021e0f6..cbc239a68 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.py index 7762e1ea8..f788ce7e1 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.pyi index 0f601f412..23235da1c 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/schemas.py index 354624dbb..28c17e77a 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-in-union/python/python_pydantic_list_in_union/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/api_client.py index 50e0e3d13..566535b6b 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_list_response.pydantic.test_fetch_response import TestFetchResponse +from python_pydantic_list_response.pydantic.test_fetch_response_item import TestFetchResponseItem + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/configuration.py index 5f68c3a3b..dbba3a1e8 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/exceptions.py index b10ab1b62..e938a3b8f 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.py index cf9eeb80d..ddfed1693 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.pyi index 520584101..f281209c2 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/schemas.py index 57e845836..5c863a685 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-list-response/python/python_pydantic_list_response/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/api_client.py index 3b86e2563..ecdf7fb96 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,13 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_nested_union_with_list_and_str.pydantic.generic_image_content import GenericImageContent +from python_pydantic_nested_union_with_list_and_str.pydantic.generic_text_content import GenericTextContent +from python_pydantic_nested_union_with_list_and_str.pydantic.test_chat_message import TestChatMessage +from python_pydantic_nested_union_with_list_and_str.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +102,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +128,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +145,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/configuration.py index 43eba7c67..f63c429e7 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/exceptions.py index 39c26ba20..8584383e4 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.py index fa1ee406e..0c6212957 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.pyi index 05fcdb2af..40f0b03cb 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/schemas.py index 8e411826f..3b34e28de 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nested-union-with-list-and-str/python/python_pydantic_nested_union_with_list_and_str/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/api_client.py index 7f250bfbf..3a81ebfa7 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_nullable_string.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/configuration.py index 3f9a271df..001ffe631 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/exceptions.py index 3f177af95..dc6ac6a3d 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.py index e70ff01b9..4a6fbe8c5 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.pyi index 90c73508b..60460d7e7 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/schemas.py index 52c0b0f85..1848f6e08 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-nullable-string/python/python_pydantic_nullable_string/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/api_client.py index cfab48215..ffb201b04 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/configuration.py index 1b50f8912..4790cf350 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/exceptions.py index 0123d3718..86141ed0e 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.py index d0e424bac..18d96d952 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.py @@ -265,6 +265,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.pyi index 3c3bfcc73..9707e677c 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/paths/simple_endpoint/get.pyi @@ -257,6 +257,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/schemas.py index d4822485c..e4884fed7 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-raw-http-doc-with-top-level-configuration/python/python_pydantic_raw_http_doc_with_top_level_configuration/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/api_client.py index e799d7579..c792b19e9 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,12 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_recursively_convert_to_models.pydantic.inner import Inner +from python_pydantic_recursively_convert_to_models.pydantic.list_inner import ListInner +from python_pydantic_recursively_convert_to_models.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +101,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +127,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +144,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/configuration.py index 55ce6ab8f..e2aaf9ddf 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/exceptions.py index bc380bdd1..25a1ff168 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.py index 1476a3a38..a3a072cb3 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.py @@ -268,6 +268,7 @@ def list( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_mapped_args( ) return self._list_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_mapped_args( ) return self._list_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.pyi index f6ce87b98..f144077f9 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/_list/get.pyi @@ -260,6 +260,7 @@ class ListRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_mapped_args( ) return self._list_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_mapped_args( ) return self._list_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.py index 7f5eda949..8d02161d2 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.pyi index 86bade06a..f4a930915 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/paths/object/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/schemas.py index 17d9c6a04..cf48a761a 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-recursively-convert-to-models/python/python_pydantic_recursively_convert_to_models/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/api_client.py index c3475a547..2dae1b402 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,11 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_reserved_namespace_model.pydantic.inner import Inner +from python_pydantic_reserved_namespace_model.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +100,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +126,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +143,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/configuration.py index df2be016f..04074def5 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/exceptions.py index eb3b64ecf..51d8c01c7 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.py index b941788ef..82d4cd030 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.pyi index 0e118b319..e82f8d619 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/schemas.py index dbd27b067..04dccf7e3 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-reserved-namespace-model/python/python_pydantic_reserved_namespace_model/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/api_client.py index 4592e81a7..11925e3b6 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,13 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_response_as_param.pydantic.attack import Attack +from python_pydantic_response_as_param.pydantic.attack_result import AttackResult +from python_pydantic_response_as_param.pydantic.equipment import Equipment +from python_pydantic_response_as_param.pydantic.sword import Sword + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +102,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +128,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +145,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/configuration.py index 4d248d886..bc79eeadc 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/exceptions.py index 1b7b6978a..f7882a173 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.py index db74c66a7..01eed06e5 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.py @@ -331,6 +331,7 @@ def attack_monster( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Attack a monster with the (pydantic) sword from your equipment """ args = self._attack_monster_mapped_args( monster=monster, sword=sword, @@ -403,6 +404,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Attack a monster with the (pydantic) sword from your equipment """ args = self._attack_monster_mapped_args( monster=monster, sword=sword, diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.pyi index 25f54f24a..beb78e0ec 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/attack_monster/post.pyi @@ -323,6 +323,7 @@ class AttackMonsterRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Attack a monster with the (pydantic) sword from your equipment """ args = self._attack_monster_mapped_args( monster=monster, sword=sword, @@ -395,6 +396,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Attack a monster with the (pydantic) sword from your equipment """ args = self._attack_monster_mapped_args( monster=monster, sword=sword, diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.py index c4174705d..2f320a312 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.py @@ -268,6 +268,7 @@ def retrieve_equipment( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Receive a pydantic response which will subsequently be used as a parameter in another endpoint. """ args = self._retrieve_equipment_mapped_args( ) return self._retrieve_equipment_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Receive a pydantic response which will subsequently be used as a parameter in another endpoint. """ args = self._retrieve_equipment_mapped_args( ) return self._retrieve_equipment_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.pyi index 54b52fff7..218f4d70e 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/paths/retrieve_equipment/get.pyi @@ -260,6 +260,7 @@ class RetrieveEquipmentRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Receive a pydantic response which will subsequently be used as a parameter in another endpoint. """ args = self._retrieve_equipment_mapped_args( ) return self._retrieve_equipment_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Receive a pydantic response which will subsequently be used as a parameter in another endpoint. """ args = self._retrieve_equipment_mapped_args( ) return self._retrieve_equipment_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/schemas.py index d5615abdb..39919eb7d 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-as-param/python/python_pydantic_response_as_param/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/api_client.py index 9357ddcab..037eb109e 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_response_with_none_fieldvalue.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/configuration.py index ec42d0c01..ed33c2888 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/exceptions.py index 9cfdea403..d9ab26778 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.py index f5dc3b084..2d65714ab 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.pyi index a311e8b80..2b2fc3093 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/paths/test/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/schemas.py index a145870f2..0f83757e6 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-response-with-none-fieldvalue/python/python_pydantic_response_with_none_fieldvalue/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/api_client.py index f0fa3e7f0..48fd65473 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,13 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic.pydantic.test_fetch400_response import TestFetch400Response +from python_pydantic.pydantic.test_fetch500_response import TestFetch500Response +from python_pydantic.pydantic.test_fetch_response import TestFetchResponse +from python_pydantic.pydantic.test_reserved_word import TestReservedWord + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +102,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +128,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +145,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/configuration.py index 7f31a18b8..545505091 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/exceptions.py index 00289c138..598dc7227 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.py index ca01152e2..a199a6b3f 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.py @@ -266,6 +266,7 @@ def reserved_word( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Reserved word in Python """ args = self._reserved_word_mapped_args( ) return self._reserved_word_oapg( @@ -320,6 +321,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Reserved word in Python """ args = self._reserved_word_mapped_args( ) return self._reserved_word_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.pyi index 36de9bafb..673298ef9 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/reserved_word/get.pyi @@ -258,6 +258,7 @@ class ReservedWordRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Reserved word in Python """ args = self._reserved_word_mapped_args( ) return self._reserved_word_oapg( @@ -312,6 +313,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Reserved word in Python """ args = self._reserved_word_mapped_args( ) return self._reserved_word_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.py index 564babe6d..398ab8753 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.py @@ -386,6 +386,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -450,6 +451,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.pyi index 9dce362e4..7fb824b5c 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/paths/simple_endpoint/get.pyi @@ -376,6 +376,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -440,6 +441,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/schemas.py index e34fc5bf0..0cb352988 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-responses/python/python_pydantic/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/api_client.py index 86149d2c5..2f6075d33 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_schema_with_underscores_in_name.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/configuration.py index 9ae54cb4c..3d28077fd 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/exceptions.py index 2104c286b..b6c6a31b0 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.py index 1d2e78b4a..a4e88c70c 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.pyi index ba043cae1..e97892a10 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/schemas.py index be54722be..4d59e400e 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-schema-with-underscores-in-name/python/python_pydantic_schema_with_underscores_in_name/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/api_client.py b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/api_client.py index 9158b3ef4..2d1bd9e44 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,10 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_pydantic_union.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +99,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +125,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +142,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/configuration.py b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/configuration.py index 2f8d065a1..0d471af0b 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/exceptions.py b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/exceptions.py index a6a1568d5..c71bb6f6d 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.py index ab0259726..1f28340d0 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.pyi index 69dc4b314..003795acd 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/schemas.py b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/schemas.py index c6707ecb4..30f2a99c1 100644 --- a/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-pydantic-union/python/python_pydantic_union/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/api_client.py b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/api_client.py index 0717a4c65..62999be85 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,9 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +98,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +124,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +141,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/configuration.py b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/configuration.py index 569224c36..f7139702c 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/exceptions.py b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/exceptions.py index dfa805b86..a7339fab3 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.py index 354fa7ee1..b256b8558 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.py @@ -265,6 +265,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.pyi index a5bb4ddd2..f3f6fba43 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/paths/simple_endpoint/get.pyi @@ -257,6 +257,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/schemas.py b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/schemas.py index 752099dac..28518754c 100644 --- a/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-readme-header-snippet/python/python_readme_header_snippet/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/api_client.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/api_client.py index 1ea0788ac..a2274f828 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/api_client.py @@ -29,6 +29,8 @@ from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -52,6 +54,7 @@ unset, ) + @dataclass class MappedArgs: body: typing.Any = None diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/configuration.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/configuration.py index b29602112..7477a46e6 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/configuration.py @@ -143,10 +143,16 @@ def __init__(self, host=None, else: self.api_key = api_key if client_id: + if type(client_id) is not str: + raise ClientConfigurationError("client_id must be a string") self.api_key['PartnerClientId'] = client_id if signature: + if type(signature) is not str: + raise ClientConfigurationError("signature must be a string") self.api_key['PartnerSignature'] = signature if timestamp: + if type(timestamp) is not str: + raise ClientConfigurationError("timestamp must be a string") self.api_key['PartnerTimestamp'] = timestamp """dict to store API key(s) """ diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/exceptions.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/exceptions.py index a58bf3309..55c6bef23 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.py index 0b648d0d8..76dddf0f2 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.py @@ -410,6 +410,7 @@ def list_user_accounts( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_user_accounts_mapped_args( query_params=query_params, user_id=user_id, @@ -454,6 +455,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_user_accounts_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.pyi index d3bc2b8fa..7dadf0f03 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts/get.pyi @@ -399,6 +399,7 @@ class ListUserAccounts(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_user_accounts_mapped_args( query_params=query_params, user_id=user_id, @@ -443,6 +444,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_user_accounts_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.py index 399deba42..60c21df00 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.py @@ -454,6 +454,7 @@ def get_user_account_details( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_details_mapped_args( query_params=query_params, path_params=path_params, @@ -508,6 +509,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_details_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.pyi index 4c4aa634d..7ee5a67fd 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/get.pyi @@ -443,6 +443,7 @@ class GetUserAccountDetails(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_details_mapped_args( query_params=query_params, path_params=path_params, @@ -497,6 +498,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_details_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.py index 674e0deaf..333282a22 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.py @@ -479,6 +479,7 @@ def update_user_account( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_user_account_mapped_args( query_params=query_params, path_params=path_params, @@ -533,6 +534,7 @@ def put( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_user_account_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.pyi index c895605ce..f14c16295 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id/put.pyi @@ -468,6 +468,7 @@ class UpdateUserAccount(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_user_account_mapped_args( query_params=query_params, path_params=path_params, @@ -522,6 +523,7 @@ class ApiForput(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_user_account_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.py index 7921307c2..59d9525be 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.py @@ -479,6 +479,7 @@ def get_user_account_balance( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ A list of account balances for the specified account (one per currency that the account holds). """ args = self._get_user_account_balance_mapped_args( query_params=query_params, path_params=path_params, @@ -533,6 +534,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ A list of account balances for the specified account (one per currency that the account holds). """ args = self._get_user_account_balance_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.pyi index a604c5775..b3d9edc73 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_balances/get.pyi @@ -468,6 +468,7 @@ class GetUserAccountBalance(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ A list of account balances for the specified account (one per currency that the account holds). """ args = self._get_user_account_balance_mapped_args( query_params=query_params, path_params=path_params, @@ -522,6 +523,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ A list of account balances for the specified account (one per currency that the account holds). """ args = self._get_user_account_balance_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.py index d2d2e5589..d7d9b16ae 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.py @@ -489,6 +489,7 @@ def get_user_holdings( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_holdings_mapped_args( query_params=query_params, path_params=path_params, @@ -541,6 +542,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_holdings_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.pyi index 9ee009381..4e784c03a 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_holdings/get.pyi @@ -476,6 +476,7 @@ class GetUserHoldings(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_holdings_mapped_args( query_params=query_params, path_params=path_params, @@ -528,6 +529,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_holdings_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.py index ea068ce8a..f8422b88f 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.py @@ -640,6 +640,7 @@ def get_option_strategy( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_option_strategy_mapped_args( body=body, query_params=query_params, @@ -710,6 +711,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_option_strategy_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.pyi index f6d0d9679..cc2957f8d 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy/post.pyi @@ -623,6 +623,7 @@ class GetOptionStrategy(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_option_strategy_mapped_args( body=body, query_params=query_params, @@ -693,6 +694,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_option_strategy_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.py index 2a21cc628..5973dce0f 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.py @@ -464,6 +464,7 @@ def get_options_strategy_quote( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_strategy_quote_mapped_args( query_params=query_params, path_params=path_params, @@ -520,6 +521,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_strategy_quote_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.pyi index 1d8afd59b..051cca3db 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id/get.pyi @@ -453,6 +453,7 @@ class GetOptionsStrategyQuote(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_strategy_quote_mapped_args( query_params=query_params, path_params=path_params, @@ -509,6 +510,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_strategy_quote_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.py index d5be042c5..e7641e806 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.py @@ -627,6 +627,7 @@ def place_option_strategy( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_option_strategy_mapped_args( body=body, query_params=query_params, @@ -701,6 +702,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_option_strategy_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.pyi index fa690da67..c65b0bc35 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_option_strategy_option_strategy_id_execute/post.pyi @@ -616,6 +616,7 @@ class PlaceOptionStrategy(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_option_strategy_mapped_args( body=body, query_params=query_params, @@ -690,6 +691,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_option_strategy_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.py index a57dfe535..e555e5fe9 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.py @@ -473,6 +473,7 @@ def list_option_holdings( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_option_holdings_mapped_args( query_params=query_params, path_params=path_params, @@ -525,6 +526,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_option_holdings_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.pyi index a42518606..54f3243f3 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options/get.pyi @@ -462,6 +462,7 @@ class ListOptionHoldings(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_option_holdings_mapped_args( query_params=query_params, path_params=path_params, @@ -514,6 +515,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_option_holdings_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.py index 471fd80fd..fe51a3f31 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.py @@ -465,6 +465,7 @@ def get_options_chain( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_chain_mapped_args( query_params=query_params, path_params=path_params, @@ -521,6 +522,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_chain_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.pyi index 5c4047150..87c162102 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_options_chain/get.pyi @@ -454,6 +454,7 @@ class GetOptionsChain(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_chain_mapped_args( query_params=query_params, path_params=path_params, @@ -510,6 +511,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_options_chain_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.py index f4cdca7a2..09241b421 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.py @@ -539,6 +539,7 @@ def get_user_account_orders( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetch all recent orders from a user's account. """ args = self._get_user_account_orders_mapped_args( query_params=query_params, path_params=path_params, @@ -599,6 +600,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetch all recent orders from a user's account. """ args = self._get_user_account_orders_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.pyi index 3349303fb..f68ba202f 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders/get.pyi @@ -516,6 +516,7 @@ class GetUserAccountOrders(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetch all recent orders from a user's account. """ args = self._get_user_account_orders_mapped_args( query_params=query_params, path_params=path_params, @@ -576,6 +577,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Fetch all recent orders from a user's account. """ args = self._get_user_account_orders_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.py index 08ac519bd..e4ed65a52 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.py @@ -581,6 +581,7 @@ def cancel_user_account_order( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_user_account_order_mapped_args( body=body, query_params=query_params, @@ -643,6 +644,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_user_account_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.pyi index 67fad1edb..2ca4da27b 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_orders_cancel/post.pyi @@ -569,6 +569,7 @@ class CancelUserAccountOrder(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_user_account_order_mapped_args( body=body, query_params=query_params, @@ -631,6 +632,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_user_account_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.py index 5d995206b..300fcf1cb 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.py @@ -479,6 +479,7 @@ def get_user_account_positions( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_positions_mapped_args( query_params=query_params, path_params=path_params, @@ -533,6 +534,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_positions_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.pyi index 2ff987866..491c98abb 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_positions/get.pyi @@ -468,6 +468,7 @@ class GetUserAccountPositions(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_positions_mapped_args( query_params=query_params, path_params=path_params, @@ -522,6 +523,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_positions_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.py index 8690804ad..a83e2ff89 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.py @@ -481,6 +481,7 @@ def get_user_account_quotes( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_quotes_mapped_args( query_params=query_params, path_params=path_params, @@ -541,6 +542,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_quotes_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.pyi index 7bfa0973b..cdd69916d 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_quotes/get.pyi @@ -470,6 +470,7 @@ class GetUserAccountQuotes(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_quotes_mapped_args( query_params=query_params, path_params=path_params, @@ -530,6 +531,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_account_quotes_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.py index 372344bec..8688be3ed 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.py @@ -536,6 +536,7 @@ def symbol_search_user_account( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._symbol_search_user_account_mapped_args( body=body, query_params=query_params, @@ -600,6 +601,7 @@ def post( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._symbol_search_user_account_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.pyi index 92181c50c..30f2d905a 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/accounts_account_id_symbols/post.pyi @@ -525,6 +525,7 @@ class SymbolSearchUserAccount(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._symbol_search_user_account_mapped_args( body=body, query_params=query_params, @@ -589,6 +590,7 @@ class ApiForpost(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._symbol_search_user_account_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.py index eada9a9b8..da2b7eb1a 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.py @@ -490,6 +490,7 @@ def get_activities( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns activities (transactions) for a user. Specifying start and end date is highly recommended for better performance """ args = self._get_activities_mapped_args( query_params=query_params, user_id=user_id, @@ -554,6 +555,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns activities (transactions) for a user. Specifying start and end date is highly recommended for better performance """ args = self._get_activities_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.pyi index 38ad4df32..a67307e92 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/activities/get.pyi @@ -479,6 +479,7 @@ class GetActivities(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns activities (transactions) for a user. Specifying start and end date is highly recommended for better performance """ args = self._get_activities_mapped_args( query_params=query_params, user_id=user_id, @@ -543,6 +544,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns activities (transactions) for a user. Specifying start and end date is highly recommended for better performance """ args = self._get_activities_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.py index d4e9aac68..3352790ce 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.py @@ -410,6 +410,7 @@ def list_brokerage_authorizations( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_brokerage_authorizations_mapped_args( query_params=query_params, user_id=user_id, @@ -454,6 +455,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_brokerage_authorizations_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.pyi index 9332854c0..6379eacfc 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations/get.pyi @@ -399,6 +399,7 @@ class ListBrokerageAuthorizations(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_brokerage_authorizations_mapped_args( query_params=query_params, user_id=user_id, @@ -443,6 +444,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_brokerage_authorizations_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.py index 68ade1598..562a1f568 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.py @@ -468,6 +468,7 @@ def remove_brokerage_authorization( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._remove_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, @@ -522,6 +523,7 @@ def delete( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._remove_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.pyi index c107ca4ba..419b7a743 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/delete.pyi @@ -455,6 +455,7 @@ class RemoveBrokerageAuthorization(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._remove_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, @@ -509,6 +510,7 @@ class ApiFordelete(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._remove_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.py index e7a842fc2..d48456238 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.py @@ -454,6 +454,7 @@ def detail_brokerage_authorization( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._detail_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, @@ -508,6 +509,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._detail_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.pyi index 0865a4dfb..db4ff4a60 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/authorizations_authorization_id/get.pyi @@ -443,6 +443,7 @@ class DetailBrokerageAuthorization(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._detail_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, @@ -497,6 +498,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._detail_brokerage_authorization_mapped_args( query_params=query_params, path_params=path_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.py index f3f7ceb9e..26a1f53e6 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.py @@ -392,6 +392,7 @@ def list_all_brokerage_authorization_type( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerage_authorization_type_mapped_args( query_params=query_params, brokerage=brokerage, @@ -432,6 +433,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerage_authorization_type_mapped_args( query_params=query_params, brokerage=brokerage, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.pyi index c0b2ba09d..1760d83c0 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerage_authorization_types/get.pyi @@ -381,6 +381,7 @@ class ListAllBrokerageAuthorizationType(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerage_authorization_type_mapped_args( query_params=query_params, brokerage=brokerage, @@ -421,6 +422,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerage_authorization_type_mapped_args( query_params=query_params, brokerage=brokerage, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.py index b694240de..cf8f14a6c 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.py @@ -321,6 +321,7 @@ def list_all_brokerages( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerages_mapped_args( ) return self._list_all_brokerages_oapg( @@ -351,6 +352,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerages_mapped_args( ) return self._list_all_brokerages_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.pyi index aebdecfa8..28017499b 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/brokerages/get.pyi @@ -310,6 +310,7 @@ class ListAllBrokerages(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerages_mapped_args( ) return self._list_all_brokerages_oapg( @@ -340,6 +341,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_brokerages_mapped_args( ) return self._list_all_brokerages_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.py index ff4176eac..535511fa9 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.py @@ -321,6 +321,7 @@ def list_all_currencies( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_mapped_args( ) return self._list_all_currencies_oapg( @@ -351,6 +352,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_mapped_args( ) return self._list_all_currencies_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.pyi index 57d9ffbc5..69b4b27f7 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies/get.pyi @@ -310,6 +310,7 @@ class ListAllCurrencies(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_mapped_args( ) return self._list_all_currencies_oapg( @@ -340,6 +341,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_mapped_args( ) return self._list_all_currencies_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.py index 53d128ea3..72a63dd86 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.py @@ -291,6 +291,7 @@ def list_all_currencies_rates( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_rates_mapped_args( ) return self._list_all_currencies_rates_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_rates_mapped_args( ) return self._list_all_currencies_rates_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.pyi index 70d02bbb3..4930f6cdb 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates/get.pyi @@ -281,6 +281,7 @@ class ListAllCurrenciesRates(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_rates_mapped_args( ) return self._list_all_currencies_rates_oapg( @@ -309,6 +310,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._list_all_currencies_rates_mapped_args( ) return self._list_all_currencies_rates_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.py index ff769b8e9..c72b328f3 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.py @@ -335,6 +335,7 @@ def get_currency_exchange_rate_pair( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_currency_exchange_rate_pair_mapped_args( path_params=path_params, currency_pair=currency_pair, @@ -373,6 +374,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_currency_exchange_rate_pair_mapped_args( path_params=path_params, currency_pair=currency_pair, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.pyi index c9669eb43..8627a96fb 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/currencies_rates_currency_pair/get.pyi @@ -325,6 +325,7 @@ class GetCurrencyExchangeRatePair(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_currency_exchange_rate_pair_mapped_args( path_params=path_params, currency_pair=currency_pair, @@ -363,6 +364,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_currency_exchange_rate_pair_mapped_args( path_params=path_params, currency_pair=currency_pair, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.py index 8a82085cc..bcdc7ddaf 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.py @@ -291,6 +291,7 @@ def get_stock_exchanges( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_stock_exchanges_mapped_args( ) return self._get_stock_exchanges_oapg( @@ -319,6 +320,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_stock_exchanges_mapped_args( ) return self._get_stock_exchanges_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.pyi index 160b533f2..bf8214b0f 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/exchanges/get.pyi @@ -281,6 +281,7 @@ class GetStockExchanges(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_stock_exchanges_mapped_args( ) return self._get_stock_exchanges_oapg( @@ -309,6 +310,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_stock_exchanges_mapped_args( ) return self._get_stock_exchanges_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.py index 3f06b8bfd..e5aeec4b0 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.py @@ -463,6 +463,7 @@ def get_all_user_holdings( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_all_user_holdings_mapped_args( query_params=query_params, user_id=user_id, @@ -511,6 +512,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_all_user_holdings_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.pyi index dc1bd6e27..26286392f 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/holdings/get.pyi @@ -450,6 +450,7 @@ class GetAllUserHoldings(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_all_user_holdings_mapped_args( query_params=query_params, user_id=user_id, @@ -498,6 +499,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_all_user_holdings_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.py index 5899af0df..ed2773e09 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.py @@ -469,6 +469,7 @@ def get_reporting_custom_range( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns performance information (contributions, dividends, rate of return, etc) for a specific timeframe. Please note that Total Equity Timeframe and Rate of Returns are experimental features. Please contact support@snaptrade.com if you notice any inconsistencies. """ args = self._get_reporting_custom_range_mapped_args( query_params=query_params, start_date=start_date, @@ -535,6 +536,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns performance information (contributions, dividends, rate of return, etc) for a specific timeframe. Please note that Total Equity Timeframe and Rate of Returns are experimental features. Please contact support@snaptrade.com if you notice any inconsistencies. """ args = self._get_reporting_custom_range_mapped_args( query_params=query_params, start_date=start_date, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.pyi index c11b5c8d3..9cb4f31a4 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/performance_custom/get.pyi @@ -458,6 +458,7 @@ class GetReportingCustomRange(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns performance information (contributions, dividends, rate of return, etc) for a specific timeframe. Please note that Total Equity Timeframe and Rate of Returns are experimental features. Please contact support@snaptrade.com if you notice any inconsistencies. """ args = self._get_reporting_custom_range_mapped_args( query_params=query_params, start_date=start_date, @@ -524,6 +525,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns performance information (contributions, dividends, rate of return, etc) for a specific timeframe. Please note that Total Equity Timeframe and Rate of Returns are experimental features. Please contact support@snaptrade.com if you notice any inconsistencies. """ args = self._get_reporting_custom_range_mapped_args( query_params=query_params, start_date=start_date, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.py index 8e95974f7..64de66525 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.py @@ -287,6 +287,7 @@ def check( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Check whether the API is operational and verify timestamps. """ args = self._check_mapped_args( ) return self._check_oapg( @@ -317,6 +318,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Check whether the API is operational and verify timestamps. """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.pyi index 60fc641ea..8700f492a 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/root/get.pyi @@ -281,6 +281,7 @@ class Check(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Check whether the API is operational and verify timestamps. """ args = self._check_mapped_args( ) return self._check_oapg( @@ -311,6 +312,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ Check whether the API is operational and verify timestamps. """ args = self._check_mapped_args( ) return self._check_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.py index 34ce5a975..2e4725345 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.py @@ -321,6 +321,7 @@ def get_security_types( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ List security types available on SnapTrade. """ args = self._get_security_types_mapped_args( ) return self._get_security_types_oapg( @@ -351,6 +352,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ List security types available on SnapTrade. """ args = self._get_security_types_mapped_args( ) return self._get_security_types_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.pyi index 084f97855..c418c656e 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/security_types/get.pyi @@ -310,6 +310,7 @@ class GetSecurityTypes(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ List security types available on SnapTrade. """ args = self._get_security_types_mapped_args( ) return self._get_security_types_oapg( @@ -340,6 +341,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ List security types available on SnapTrade. """ args = self._get_security_types_mapped_args( ) return self._get_security_types_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.py index eb859b7eb..44fc7ee55 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.py @@ -457,6 +457,7 @@ def session_events( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._session_events_mapped_args( query_params=query_params, partner_client_id=partner_client_id, @@ -505,6 +506,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._session_events_mapped_args( query_params=query_params, partner_client_id=partner_client_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.pyi index b0be5fa3b..414fbb193 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/session_events/get.pyi @@ -446,6 +446,7 @@ class SessionEvents(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._session_events_mapped_args( query_params=query_params, partner_client_id=partner_client_id, @@ -494,6 +495,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._session_events_mapped_args( query_params=query_params, partner_client_id=partner_client_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.py index 05c2a332f..583c0ea80 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.py @@ -427,6 +427,7 @@ def delete_snap_trade_user( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Deletes a user you've registered over the SnapTrade API, and any data associated with them or their investment accounts. """ args = self._delete_snap_trade_user_mapped_args( query_params=query_params, user_id=user_id, @@ -465,6 +466,7 @@ def delete( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Deletes a user you've registered over the SnapTrade API, and any data associated with them or their investment accounts. """ args = self._delete_snap_trade_user_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.pyi index 0caa42b50..4c43aa6b2 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_delete_user/delete.pyi @@ -413,6 +413,7 @@ class DeleteSnapTradeUser(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Deletes a user you've registered over the SnapTrade API, and any data associated with them or their investment accounts. """ args = self._delete_snap_trade_user_mapped_args( query_params=query_params, user_id=user_id, @@ -451,6 +452,7 @@ class ApiFordelete(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Deletes a user you've registered over the SnapTrade API, and any data associated with them or their investment accounts. """ args = self._delete_snap_trade_user_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.py index 8c06f85df..74361d327 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.py @@ -444,6 +444,7 @@ def get_user_jwt( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_jwt_mapped_args( query_params=query_params, user_id=user_id, @@ -486,6 +487,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_jwt_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.pyi index 617f19ba7..56f84f26e 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_encrypted_jwt/get.pyi @@ -430,6 +430,7 @@ class GetUserJwt(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_jwt_mapped_args( query_params=query_params, user_id=user_id, @@ -472,6 +473,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_user_jwt_mapped_args( query_params=query_params, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.py index 3f2499018..5145def88 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.py @@ -338,6 +338,7 @@ def list_snap_trade_users( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns a list of users you've registered over the SnapTrade API. """ args = self._list_snap_trade_users_mapped_args( ) return self._list_snap_trade_users_oapg( @@ -366,6 +367,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns a list of users you've registered over the SnapTrade API. """ args = self._list_snap_trade_users_mapped_args( ) return self._list_snap_trade_users_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.pyi index ff73f34e6..55e58aec2 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_list_users/get.pyi @@ -325,6 +325,7 @@ class ListSnapTradeUsers(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns a list of users you've registered over the SnapTrade API. """ args = self._list_snap_trade_users_mapped_args( ) return self._list_snap_trade_users_oapg( @@ -353,6 +354,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Returns a list of users you've registered over the SnapTrade API. """ args = self._list_snap_trade_users_mapped_args( ) return self._list_snap_trade_users_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.py index a3bd6c22e..c24ef1fe2 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.py @@ -569,6 +569,7 @@ def login_snap_trade_user( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Logs in a SnapTrade user and returns an authenticated connection portal URL for them to use to connect a brokerage account. """ args = self._login_snap_trade_user_mapped_args( body=body, query_params=query_params, @@ -641,6 +642,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Logs in a SnapTrade user and returns an authenticated connection portal URL for them to use to connect a brokerage account. """ args = self._login_snap_trade_user_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.pyi index 41438e46c..83790bfac 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_login/post.pyi @@ -555,6 +555,7 @@ class LoginSnapTradeUser(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Logs in a SnapTrade user and returns an authenticated connection portal URL for them to use to connect a brokerage account. """ args = self._login_snap_trade_user_mapped_args( body=body, query_params=query_params, @@ -627,6 +628,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Logs in a SnapTrade user and returns an authenticated connection portal URL for them to use to connect a brokerage account. """ args = self._login_snap_trade_user_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.py index 11c20ab13..e49476758 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.py @@ -355,6 +355,7 @@ def get_partner_info( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_partner_info_mapped_args( ) return self._get_partner_info_oapg( @@ -383,6 +384,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_partner_info_mapped_args( ) return self._get_partner_info_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.pyi index 9195cbd84..a025a5bc1 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_partners/get.pyi @@ -341,6 +341,7 @@ class GetPartnerInfo(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_partner_info_mapped_args( ) return self._get_partner_info_oapg( @@ -369,6 +370,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_partner_info_mapped_args( ) return self._get_partner_info_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.py index fb20b97bc..8a7abb992 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.py @@ -400,6 +400,7 @@ def register_snap_trade_user( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._register_snap_trade_user_mapped_args( body=body, user_id=user_id, @@ -438,6 +439,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._register_snap_trade_user_mapped_args( body=body, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.pyi index 49e0d1cd8..5d2c971be 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_register_user/post.pyi @@ -387,6 +387,7 @@ class RegisterSnapTradeUser(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._register_snap_trade_user_mapped_args( body=body, user_id=user_id, @@ -425,6 +426,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._register_snap_trade_user_mapped_args( body=body, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.py index 4ab77a7aa..74c221f91 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.py @@ -404,6 +404,7 @@ def reset_snap_trade_user_secret( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._reset_snap_trade_user_secret_mapped_args( body=body, user_id=user_id, @@ -446,6 +447,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._reset_snap_trade_user_secret_mapped_args( body=body, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.pyi index 3540df10b..23a17b2d4 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/snap_trade_reset_user_secret/post.pyi @@ -391,6 +391,7 @@ class ResetSnapTradeUserSecret(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._reset_snap_trade_user_secret_mapped_args( body=body, user_id=user_id, @@ -433,6 +434,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._reset_snap_trade_user_secret_mapped_args( body=body, user_id=user_id, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.py index 73e2b2155..89f0ca74f 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.py @@ -378,6 +378,7 @@ def get_symbols( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_mapped_args( body=body, substring=substring, @@ -418,6 +419,7 @@ def post( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_mapped_args( body=body, substring=substring, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.pyi index 0c844d594..d9879b539 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols/post.pyi @@ -367,6 +367,7 @@ class GetSymbols(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_mapped_args( body=body, substring=substring, @@ -407,6 +408,7 @@ class ApiForpost(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_mapped_args( body=body, substring=substring, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.py index 7194a0eaa..e36e331d3 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.py @@ -382,6 +382,7 @@ def get_symbols_by_ticker( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_by_ticker_mapped_args( path_params=path_params, query=query, @@ -422,6 +423,7 @@ def get( ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_by_ticker_mapped_args( path_params=path_params, query=query, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.pyi index d25e36551..274050966 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/symbols_query/get.pyi @@ -370,6 +370,7 @@ class GetSymbolsByTicker(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_by_ticker_mapped_args( path_params=path_params, query=query, @@ -410,6 +411,7 @@ class ApiForget(BaseApi): ApiResponseForDefault, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_symbols_by_ticker_mapped_args( path_params=path_params, query=query, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.py index 5a1f02f5e..aa52ea879 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.py @@ -544,6 +544,7 @@ def get_order_impact( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_order_impact_mapped_args( body=body, query_params=query_params, @@ -628,6 +629,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_order_impact_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.pyi index 2ddd5d5c7..884840aff 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_impact/post.pyi @@ -531,6 +531,7 @@ class GetOrderImpact(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_order_impact_mapped_args( body=body, query_params=query_params, @@ -615,6 +616,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_order_impact_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.py index b9871c010..18d1e9f86 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.py @@ -523,6 +523,7 @@ def place_oco_order( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_oco_order_mapped_args( body=body, query_params=query_params, @@ -581,6 +582,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_oco_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.pyi index d3045a0b1..630d6d237 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_oco/post.pyi @@ -511,6 +511,7 @@ class PlaceOcoOrder(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_oco_order_mapped_args( body=body, query_params=query_params, @@ -569,6 +570,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_oco_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.py index a4a066b99..bc75b6b96 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.py @@ -544,6 +544,7 @@ def place_force_order( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_force_order_mapped_args( body=body, query_params=query_params, @@ -628,6 +629,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_force_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.pyi index 1e3855ec0..90fb250d6 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_place/post.pyi @@ -531,6 +531,7 @@ class PlaceForceOrder(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_force_order_mapped_args( body=body, query_params=query_params, @@ -615,6 +616,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_force_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.py index fefbe6b3e..236ab24f4 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.py @@ -522,6 +522,7 @@ def place_order( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_order_mapped_args( body=body, query_params=query_params, @@ -584,6 +585,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.pyi b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.pyi index 2de573ff0..b9a537042 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.pyi +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/paths/trade_trade_id/post.pyi @@ -510,6 +510,7 @@ class PlaceOrder(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_order_mapped_args( body=body, query_params=query_params, @@ -572,6 +573,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._place_order_mapped_args( body=body, query_params=query_params, diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/schemas.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/schemas.py index d658ccbe0..def947e9a 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/schemas.py @@ -975,6 +975,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1841,7 +1875,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1876,7 +1910,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1992,6 +2026,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2054,39 +2089,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol.py index c2df6ce8a..5ada8ea00 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol.py @@ -30,6 +30,7 @@ class RequiredOptionsSymbol(TypedDict): underlying_symbol: UnderlyingSymbol + class OptionalOptionsSymbol(TypedDict, total=False): is_mini_option: bool diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol_nullable.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol_nullable.py index 4f456d073..7a21a1665 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol_nullable.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/options_symbol_nullable.py @@ -30,6 +30,7 @@ class RequiredOptionsSymbolNullable(TypedDict): underlying_symbol: UnderlyingSymbol + class OptionalOptionsSymbolNullable(TypedDict, total=False): is_mini_option: bool diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol.py index 44e227789..3344d93ab 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol.py @@ -32,6 +32,7 @@ class RequiredUniversalSymbol(TypedDict): currencies: typing.List[Currency] + class OptionalUniversalSymbol(TypedDict, total=False): description: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol_nullable.py b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol_nullable.py index 764db1cde..c27d519b8 100644 --- a/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol_nullable.py +++ b/generator/konfig-integration-tests/sdks/python-snaptrade/sdks/python/snaptrade_client/type/universal_symbol_nullable.py @@ -32,6 +32,7 @@ class RequiredUniversalSymbolNullable(TypedDict): currencies: typing.List[Currency] + class OptionalUniversalSymbolNullable(TypedDict, total=False): description: typing.Optional[str] diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/api_client.py b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/api_client.py index a23268d27..7af42cfcd 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/api_client.py @@ -29,6 +29,8 @@ from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -52,6 +54,7 @@ unset, ) + @dataclass class MappedArgs: body: typing.Any = None diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/configuration.py b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/configuration.py index 77d8736fd..3cab8a245 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key_auth: + if type(api_key_auth) is not str: + raise ClientConfigurationError("api_key_auth must be a string") self.api_key['ApiKeyAuth'] = api_key_auth else: raise ClientConfigurationError('API Key "ApiKeyAuth" is required') diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/exceptions.py b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/exceptions.py index 15b336ec5..af3cdb331 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.py index 6c08f9892..735cf155b 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.py @@ -380,6 +380,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -414,6 +415,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.pyi index cc02c8741..c5441fbdf 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/paths/simple_endpoint/get.pyi @@ -370,6 +370,7 @@ class Fetch(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) @@ -404,6 +405,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( input_parameter=input_parameter, ) diff --git a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/schemas.py b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/schemas.py index 4efcf40f7..ebd5543a3 100644 --- a/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-typeddict-responses/python/python_typeddict/schemas.py @@ -975,6 +975,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1841,7 +1875,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1876,7 +1910,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1992,6 +2026,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2054,39 +2089,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/api_client.py b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/api_client.py index bfb50f902..15ffcae45 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/api_client.py +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/api_client.py @@ -25,11 +25,14 @@ import typing_extensions import aiohttp import urllib3 -from pydantic import BaseModel, RootModel, ValidationError, ConfigDict +import pydantic +from pydantic import BaseModel, RootModel, ConfigDict from urllib3._collections import HTTPHeaderDict from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -53,6 +56,13 @@ unset, ) +# import all pydantic classes so that any type hints which are quoted due to circular imports +# are still available in the global namespace +from python_union_string_discriminator.pydantic.a import A +from python_union_string_discriminator.pydantic.b import B +from python_union_string_discriminator.pydantic.generic_schema import GenericSchema +from python_union_string_discriminator.pydantic.test_fetch_response import TestFetchResponse + @dataclass class MappedArgs: body: typing.Any = None @@ -92,7 +102,7 @@ def closest_type_match(value: typing.Any, types: typing.List[typing.Type]) -> ty try: t(**value) best_match = t - except ValidationError: + except pydantic.ValidationError: continue else: # This is a non-generic type if isinstance(value, t): @@ -118,6 +128,9 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return construct_model_instance(best_type, data) elif model is None or model is type(None): return data + # catch and convert datetime represented as string + elif isinstance(data, str) and model is dt: + return parser.parse(data) # if model is scalar value like str, number, etc. just return the value elif isinstance(data, (str, float, int, bytes, bool)): return data @@ -132,12 +145,14 @@ def construct_model_instance(model: typing.Type[T], data: typing.Any) -> T: return data elif model is dict: return data + elif model is Dictionary: + return data elif model is object: return data # if model is BaseModel, iterate over fields and recursively call elif issubclass(model, BaseModel): new_data = {} - for field_name, field_type in model.__annotations__.items(): + for field_name, field_type in typing.get_type_hints(model, globals()).items(): # get alias alias = model.model_fields[field_name].alias if alias in data: diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/configuration.py b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/configuration.py index 9b6837a1f..191694104 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/configuration.py +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/configuration.py @@ -131,6 +131,8 @@ def __init__(self, host=None, # Authentication Settings self.api_key = {} if api_key: + if type(api_key) is not str: + raise ClientConfigurationError("api_key must be a string") self.api_key['ApiKey'] = api_key else: raise ClientConfigurationError('API Key "ApiKey" is required') diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/exceptions.py b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/exceptions.py index 2bfa29b92..29cf1e005 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/exceptions.py +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/exceptions.py @@ -98,48 +98,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -190,3 +148,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.py b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.py index cac26566f..16a5eadde 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.py +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.py @@ -268,6 +268,7 @@ def fetch( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -322,6 +323,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.pyi b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.pyi index c464917e3..e8ae46d6b 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.pyi +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/paths/simple_endpoint/get.pyi @@ -260,6 +260,7 @@ class FetchRaw(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( @@ -314,6 +315,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ Provide an input parameter to receive a JSON value with properties. """ args = self._fetch_mapped_args( ) return self._fetch_oapg( diff --git a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/schemas.py b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/schemas.py index 9b8a00422..bd22a2b77 100644 --- a/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/schemas.py +++ b/generator/konfig-integration-tests/sdks/python-union-string-discriminator/python/python_union_string_discriminator/schemas.py @@ -976,6 +976,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1844,7 +1878,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1879,7 +1913,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1995,6 +2029,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2057,39 +2092,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/api_client.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/api_client.py index 25ac92962..4e2fea371 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/api_client.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/api_client.py @@ -28,6 +28,8 @@ from urllib.parse import urlparse, quote from urllib3.fields import RequestField as RequestFieldBase from urllib3.fields import guess_content_type +from dateutil import parser +from datetime import datetime as dt import frozendict @@ -51,6 +53,7 @@ unset, ) + @dataclass class MappedArgs: body: typing.Any = None diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/exceptions.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/exceptions.py index e38e910f3..20e26faa7 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/exceptions.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/exceptions.py @@ -97,48 +97,6 @@ def __str__(self): return error_message -class AnyOfValidationError(OpenApiException): - def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError]]): - self.error_list = error_list - sub_msgs: typing.List[str] = [] - for type_error in error_list: - sub_msgs.append(str(type_error)) - num_validation_errors = len(self.error_list) - if num_validation_errors == 1: - super().__init__(sub_msgs[0]) - else: - # create a string that says how many validation errors there were and - # prints each sub_msg out using a bulleted list of messages - msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") - for i, sub_msg in enumerate(sub_msgs): - msg += " {}. {}\n".format(i+1, sub_msg) - super().__init__(msg) - - -class InvalidHostConfigurationError(ClientConfigurationError): - def __init__(self, host: str, reason: str): - self.host = host - self.reason = reason - super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) - - -class MissingRequiredPropertiesError(ApiTypeError): - def __init__(self, msg: str): - super().__init__(msg) - - -class MissingRequiredParametersError(ApiTypeError): - def __init__(self, error: TypeError): - self.error = error - error_str = str(error) - self.msg = error_str - if "__new__()" in error_str: - # parse error to reformat - missing_parameters = error_str.split(":")[1].strip() - number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() - self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) - super().__init__(self.msg) - class SchemaValidationError(OpenApiException): def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, ApiTypeError]]): """ Aggregates schema validation errors @@ -189,3 +147,45 @@ def __init__(self, validation_errors: typing.List[typing.Union[ApiValueError, Ap num_validation_errors = len(self.validation_errors) self.msg = "{} invalid argument{}. {}".format(num_validation_errors, "s" if num_validation_errors > 1 else "", sub_msg) super().__init__(self.msg) + +class AnyOfValidationError(OpenApiException): + def __init__(self, error_list: typing.List[typing.Union[ApiTypeError, ApiValueError, SchemaValidationError]]): + self.error_list = error_list + sub_msgs: typing.List[str] = [] + for type_error in error_list: + sub_msgs.append(str(type_error)) + num_validation_errors = len(self.error_list) + if num_validation_errors == 1: + super().__init__(sub_msgs[0]) + else: + # create a string that says how many validation errors there were and + # prints each sub_msg out using a bulleted list of messages + msg = "{} validation error{} detected: \n".format(num_validation_errors, "s" if num_validation_errors > 1 else "") + for i, sub_msg in enumerate(sub_msgs): + msg += " {}. {}\n".format(i+1, sub_msg) + super().__init__(msg) + + +class InvalidHostConfigurationError(ClientConfigurationError): + def __init__(self, host: str, reason: str): + self.host = host + self.reason = reason + super().__init__('Invalid host: "{}", {}'.format(self.host, self.reason)) + + +class MissingRequiredPropertiesError(ApiTypeError): + def __init__(self, msg: str): + super().__init__(msg) + + +class MissingRequiredParametersError(ApiTypeError): + def __init__(self, error: TypeError): + self.error = error + error_str = str(error) + self.msg = error_str + if "__new__()" in error_str: + # parse error to reformat + missing_parameters = error_str.split(":")[1].strip() + number_of_parameters = error_str.split("missing")[1].split("required")[0].strip() + self.msg = "Missing {} required parameter{}: {}".format(number_of_parameters, "s" if int(number_of_parameters) > 1 else "", missing_parameters) + super().__init__(self.msg) diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.py index 61a116c3d..ed2d15f2d 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.py @@ -664,6 +664,7 @@ def post2( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post2_mapped_args( auto_capture=auto_capture, terms_and_conditions_accepted=terms_and_conditions_accepted, @@ -748,6 +749,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post2_mapped_args( auto_capture=auto_capture, terms_and_conditions_accepted=terms_and_conditions_accepted, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.pyi index 47add1c66..e2fb41976 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans/post.pyi @@ -642,6 +642,7 @@ class Post2(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post2_mapped_args( auto_capture=auto_capture, terms_and_conditions_accepted=terms_and_conditions_accepted, @@ -726,6 +727,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post2_mapped_args( auto_capture=auto_capture, terms_and_conditions_accepted=terms_and_conditions_accepted, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.py index 4fc8e9792..c3ba1aa53 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.py @@ -539,6 +539,7 @@ def check_eligibility( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_eligibility_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, @@ -591,6 +592,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_eligibility_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.pyi index 204ed1d02..83e158ab5 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_check_eligibility/post.pyi @@ -527,6 +527,7 @@ class CheckEligibility(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_eligibility_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, @@ -579,6 +580,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._check_eligibility_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.py index 15d1938b1..d3a066dc8 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.py @@ -658,6 +658,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post_mapped_args( auto_capture=auto_capture, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -738,6 +739,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post_mapped_args( auto_capture=auto_capture, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.pyi index 80d167ca6..497747d88 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_initiate/post.pyi @@ -636,6 +636,7 @@ class Post(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post_mapped_args( auto_capture=auto_capture, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -716,6 +717,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._post_mapped_args( auto_capture=auto_capture, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.py index 0655d6e7a..fec824113 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.py @@ -519,6 +519,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -563,6 +564,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.pyi index 60237cc86..72a1ef3fc 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number/get.pyi @@ -507,6 +507,7 @@ class Get(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -551,6 +552,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._get_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.py index c03e534e9..46dc57292 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.py @@ -519,6 +519,7 @@ def cancel( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -563,6 +564,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.pyi index 1ce95f6e7..cc9ccf2fb 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_cancel/post.pyi @@ -507,6 +507,7 @@ class Cancel(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -551,6 +552,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._cancel_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.py index 5ebd10d14..ecdb5de65 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.py @@ -594,6 +594,7 @@ def refund( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._refund_mapped_args( amount=amount, installment_plan_number=installment_plan_number, @@ -648,6 +649,7 @@ def post( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._refund_mapped_args( amount=amount, installment_plan_number=installment_plan_number, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.pyi index da01ecdfe..90ce5d424 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_refund/post.pyi @@ -582,6 +582,7 @@ class Refund(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._refund_mapped_args( amount=amount, installment_plan_number=installment_plan_number, @@ -636,6 +637,7 @@ class ApiForpost(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._refund_mapped_args( amount=amount, installment_plan_number=installment_plan_number, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.py index 20322f4aa..802da470a 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.py @@ -606,6 +606,7 @@ def update_order( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -668,6 +669,7 @@ def put( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.pyi index f0a950c82..91442e603 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_updateorder/put.pyi @@ -594,6 +594,7 @@ class UpdateOrder(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -656,6 +657,7 @@ class ApiForput(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.py index c6381db7c..82d197e6b 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.py @@ -519,6 +519,7 @@ def verify_authorization( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._verify_authorization_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -563,6 +564,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._verify_authorization_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.pyi index 4fd2d0408..3882bfa92 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_installment_plan_number_verifyauthorization/get.pyi @@ -507,6 +507,7 @@ class VerifyAuthorization(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._verify_authorization_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -551,6 +552,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._verify_authorization_mapped_args( installment_plan_number=installment_plan_number, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.py index 699e7a9c3..edbf6165a 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.py @@ -581,6 +581,7 @@ def search( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._search_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, @@ -633,6 +634,7 @@ def get( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._search_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.pyi index 68e468873..422116e69 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_search/get.pyi @@ -569,6 +569,7 @@ class Search(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._search_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, @@ -621,6 +622,7 @@ class ApiForget(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._search_mapped_args( x_splitit_idempotency_key=x_splitit_idempotency_key, x_splitit_touch_point=x_splitit_touch_point, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.py index b2768e1bc..0b8abcb34 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.py @@ -550,6 +550,7 @@ def update_order2( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order2_mapped_args( body=body, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -612,6 +613,7 @@ def put( ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order2_mapped_args( body=body, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.pyi b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.pyi index 080a93cae..796988af7 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.pyi +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/paths/api_installmentplans_updateorder/put.pyi @@ -538,6 +538,7 @@ class UpdateOrder2(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order2_mapped_args( body=body, x_splitit_idempotency_key=x_splitit_idempotency_key, @@ -600,6 +601,7 @@ class ApiForput(BaseApi): ApiResponseFor200, api_client.ApiResponseWithoutDeserialization, ]: + """ """ args = self._update_order2_mapped_args( body=body, x_splitit_idempotency_key=x_splitit_idempotency_key, diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/schemas.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/schemas.py index 9bc08428b..dfaebfb86 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/schemas.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/schemas.py @@ -974,6 +974,40 @@ def _validate_oapg( return super()._validate_oapg(arg, validation_metadata=validation_metadata) +class IntBase: + @property + def as_int_oapg(self) -> int: + try: + return self._as_int + except AttributeError: + self._as_int = int(self) + return self._as_int + + @classmethod + def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): + if isinstance(arg, decimal.Decimal): + + denominator = arg.as_integer_ratio()[-1] + if denominator != 1: + raise ApiValueError( + "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) + ) + + @classmethod + def _validate_oapg( + cls, + arg, + validation_metadata: ValidationMetadata, + ): + """ + IntBase _validate_oapg + TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only + """ + if cls._types and int not in cls._types: cls._types.add(int) + cls.__validate_format(arg, validation_metadata=validation_metadata) + return super()._validate_oapg(arg, validation_metadata=validation_metadata) + + class UUIDBase: @property @functools.lru_cache() @@ -1840,7 +1874,7 @@ def __get_oneof_class( continue try: path_to_schemas = oneof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and oneof_cls is discriminated_cls: raise ex continue @@ -1875,7 +1909,7 @@ def __get_anyof_classes( try: other_path_to_schemas = anyof_cls._validate_oapg(arg, validation_metadata=validation_metadata) - except (ApiValueError, ApiTypeError) as ex: + except (ApiValueError, ApiTypeError, SchemaValidationError) as ex: if discriminated_cls is not None and anyof_cls is discriminated_cls: raise ex exceptions.append(ex) @@ -1991,6 +2025,7 @@ class ComposedSchema( ComposedBase, DictBase, ListBase, + IntBase, NumberBase, StrBase, BoolBase, @@ -2053,39 +2088,6 @@ def __new__(cls, arg: typing.Union[decimal.Decimal, int, float], **kwargs: Confi return super().__new__(cls, arg, **kwargs) -class IntBase: - @property - def as_int_oapg(self) -> int: - try: - return self._as_int - except AttributeError: - self._as_int = int(self) - return self._as_int - - @classmethod - def __validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata): - if isinstance(arg, decimal.Decimal): - - denominator = arg.as_integer_ratio()[-1] - if denominator != 1: - raise ApiValueError( - "Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item) - ) - - @classmethod - def _validate_oapg( - cls, - arg, - validation_metadata: ValidationMetadata, - ): - """ - IntBase _validate_oapg - TODO what about types = (int, number) -> IntBase, NumberBase? We could drop int and keep number only - """ - cls.__validate_format(arg, validation_metadata=validation_metadata) - return super()._validate_oapg(arg, validation_metadata=validation_metadata) - - class IntSchema(IntBase, NumberBase, Schema, IntMixin): @classmethod diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/authorization_model.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/authorization_model.py index b71033e8e..6c79d769e 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/authorization_model.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/authorization_model.py @@ -20,6 +20,7 @@ class RequiredAuthorizationModel(TypedDict): Status: GwAuthorizationStatus + class OptionalAuthorizationModel(TypedDict, total=False): Date: datetime diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/initiate_plan_response.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/initiate_plan_response.py index a1edac2dd..54d02b6de 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/initiate_plan_response.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/initiate_plan_response.py @@ -23,6 +23,7 @@ class RequiredInitiatePlanResponse(TypedDict): Status: PlanStatus + class OptionalInitiatePlanResponse(TypedDict, total=False): InstallmentPlanNumber: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment.py index e06840423..35c73b50b 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment.py @@ -23,6 +23,7 @@ class RequiredInstallment(TypedDict): Status: InstallmentStatus + class OptionalInstallment(TypedDict, total=False): ProcessDateTime: datetime diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_request.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_request.py index ebee037d6..70d8c2483 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_request.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_request.py @@ -27,6 +27,7 @@ class RequiredInstallmentPlanCreateRequest(TypedDict): TermsAndConditionsAccepted: bool + class OptionalInstallmentPlanCreateRequest(TypedDict, total=False): Attempt3dSecure: bool diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_response.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_response.py index 8be76305f..6c3dfc90d 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_response.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_create_response.py @@ -29,6 +29,7 @@ class RequiredInstallmentPlanCreateResponse(TypedDict): Status: PlanStatus + class OptionalInstallmentPlanCreateResponse(TypedDict, total=False): InstallmentPlanNumber: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_get_response.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_get_response.py index 41225ce58..29be76d14 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_get_response.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_get_response.py @@ -30,6 +30,7 @@ class RequiredInstallmentPlanGetResponse(TypedDict): Status: PlanStatus + class OptionalInstallmentPlanGetResponse(TypedDict, total=False): InstallmentPlanNumber: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_initiate_request.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_initiate_request.py index ed08fe2d4..70c4febf3 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_initiate_request.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_initiate_request.py @@ -25,6 +25,7 @@ class RequiredInstallmentPlanInitiateRequest(TypedDict): AutoCapture: bool + class OptionalInstallmentPlanInitiateRequest(TypedDict, total=False): Attempt3dSecure: bool diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_refund_request.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_refund_request.py index 2dbc0e62f..7d432a371 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_refund_request.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_refund_request.py @@ -19,6 +19,7 @@ class RequiredInstallmentPlanRefundRequest(TypedDict): Amount: typing.Union[int, float] + class OptionalInstallmentPlanRefundRequest(TypedDict, total=False): RefundStrategy: RefundStrategy diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_update_response.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_update_response.py index 9665daa42..80b28af5f 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_update_response.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/installment_plan_update_response.py @@ -22,6 +22,7 @@ class RequiredInstallmentPlanUpdateResponse(TypedDict): ShippingStatus: ShippingStatus + class OptionalInstallmentPlanUpdateResponse(TypedDict, total=False): RefOrderNumber: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_method_model.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_method_model.py index efac89014..99068b2ff 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_method_model.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_method_model.py @@ -23,6 +23,7 @@ class RequiredPaymentMethodModel(TypedDict): Type: PaymentMethodType + class OptionalPaymentMethodModel(TypedDict, total=False): Card: CardData diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_plan_option_model.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_plan_option_model.py index fcd592982..4e7790ae8 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_plan_option_model.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/payment_plan_option_model.py @@ -25,6 +25,7 @@ class RequiredPaymentPlanOptionModel(TypedDict): LastInstallmentAmount: typing.Union[int, float] + class OptionalPaymentPlanOptionModel(TypedDict, total=False): Links: LinksModel diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data.py index b207fd183..d87590934 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data.py @@ -26,6 +26,7 @@ class RequiredPlanData(TypedDict): PurchaseMethod: PurchaseMethod + class OptionalPlanData(TypedDict, total=False): TerminalId: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data_model.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data_model.py index 70c9ce6f2..a4ea9fe79 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data_model.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/plan_data_model.py @@ -22,6 +22,7 @@ class RequiredPlanDataModel(TypedDict): PurchaseMethod: PurchaseMethod + class OptionalPlanDataModel(TypedDict, total=False): Currency: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/refund_model.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/refund_model.py index 6482cf95c..6d226ca95 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/refund_model.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/refund_model.py @@ -27,6 +27,7 @@ class RequiredRefundModel(TypedDict): CreditRefundAmount: typing.Union[int, float] + class OptionalRefundModel(TypedDict, total=False): RefundId: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/search_installment_plan_response_item.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/search_installment_plan_response_item.py index 70f685c3e..2f792bf90 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/search_installment_plan_response_item.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/search_installment_plan_response_item.py @@ -30,6 +30,7 @@ class RequiredSearchInstallmentPlanResponseItem(TypedDict): Status: PlanStatus + class OptionalSearchInstallmentPlanResponseItem(TypedDict, total=False): InstallmentPlanNumber: str diff --git a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/verify_authorization_response.py b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/verify_authorization_response.py index cb2c9a671..ebcc46553 100644 --- a/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/verify_authorization_response.py +++ b/generator/konfig-integration-tests/sdks/splitit/python-splitit/python/python_splitit_client/type/verify_authorization_response.py @@ -19,6 +19,7 @@ class RequiredVerifyAuthorizationResponse(TypedDict): IsAuthorized: bool + class OptionalVerifyAuthorizationResponse(TypedDict, total=False): AuthorizationAmount: typing.Union[int, float]