From 8123d1b5c4ffea9d7c6da1958a8e662410073d04 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 24 Jan 2023 09:57:13 -0500 Subject: [PATCH 01/10] docs: Reformat some comments and documentation (#614) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: Reformat some comments and documentation PiperOrigin-RevId: 504029060 Source-Link: https://github.com/googleapis/googleapis/commit/4d9606ecc1415ccab14796dc74ba2ffdd0633bf0 Source-Link: https://github.com/googleapis/googleapis-gen/commit/a77ae2d90dd0539409c8bad976908df613096ded Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiYTc3YWUyZDkwZGQwNTM5NDA5YzhiYWQ5NzY5MDhkZjYxMzA5NmRlZCJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot --- .../services/agents/async_client.py | 8 ++--- .../services/agents/client.py | 8 ++--- .../services/answer_records/async_client.py | 20 ++++++----- .../services/answer_records/client.py | 20 ++++++----- .../services/contexts/async_client.py | 2 +- .../services/contexts/client.py | 2 +- .../conversation_profiles/async_client.py | 2 +- .../services/conversation_profiles/client.py | 2 +- .../services/conversations/async_client.py | 6 ++-- .../services/conversations/client.py | 6 ++-- .../services/documents/async_client.py | 28 ++++++--------- .../services/documents/client.py | 28 ++++++--------- .../services/entity_types/async_client.py | 8 ++--- .../services/entity_types/client.py | 8 ++--- .../services/environments/async_client.py | 4 +-- .../services/environments/client.py | 4 +-- .../services/intents/async_client.py | 8 ++--- .../services/intents/client.py | 8 ++--- .../services/knowledge_bases/async_client.py | 2 +- .../services/knowledge_bases/client.py | 2 +- .../services/participants/async_client.py | 34 ++++++++++--------- .../services/participants/client.py | 34 ++++++++++--------- .../session_entity_types/async_client.py | 2 +- .../services/session_entity_types/client.py | 2 +- .../services/sessions/async_client.py | 13 +++---- .../services/sessions/client.py | 13 +++---- .../services/versions/async_client.py | 2 +- .../services/versions/client.py | 2 +- ...t_metadata_google.cloud.dialogflow.v2.json | 2 +- ...adata_google.cloud.dialogflow.v2beta1.json | 2 +- 30 files changed, 132 insertions(+), 150 deletions(-) diff --git a/google/cloud/dialogflow_v2beta1/services/agents/async_client.py b/google/cloud/dialogflow_v2beta1/services/agents/async_client.py index 3d5b11503..0eea461fd 100644 --- a/google/cloud/dialogflow_v2beta1/services/agents/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/agents/async_client.py @@ -600,7 +600,7 @@ async def sample_search_agents(): Returns: google.cloud.dialogflow_v2beta1.services.agents.pagers.SearchAgentsAsyncPager: The response message for - [Agents.SearchAgents][google.cloud.dialogflow.v2beta1.Agents.SearchAgents]. + [Agents.SearchAgents][google.cloud.dialogflow.v2beta1.Agents.SearchAgents]. Iterating over this object will yield results and resolve additional pages automatically. @@ -869,10 +869,8 @@ async def sample_export_agent(): google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.ExportAgentResponse` - The response message for - [Agents.ExportAgent][google.cloud.dialogflow.v2beta1.Agents.ExportAgent]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.ExportAgentResponse` The response message for + [Agents.ExportAgent][google.cloud.dialogflow.v2beta1.Agents.ExportAgent]. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflow_v2beta1/services/agents/client.py b/google/cloud/dialogflow_v2beta1/services/agents/client.py index de07c20fe..91ecdf50f 100644 --- a/google/cloud/dialogflow_v2beta1/services/agents/client.py +++ b/google/cloud/dialogflow_v2beta1/services/agents/client.py @@ -828,7 +828,7 @@ def sample_search_agents(): Returns: google.cloud.dialogflow_v2beta1.services.agents.pagers.SearchAgentsPager: The response message for - [Agents.SearchAgents][google.cloud.dialogflow.v2beta1.Agents.SearchAgents]. + [Agents.SearchAgents][google.cloud.dialogflow.v2beta1.Agents.SearchAgents]. Iterating over this object will yield results and resolve additional pages automatically. @@ -1097,10 +1097,8 @@ def sample_export_agent(): google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.ExportAgentResponse` - The response message for - [Agents.ExportAgent][google.cloud.dialogflow.v2beta1.Agents.ExportAgent]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.ExportAgentResponse` The response message for + [Agents.ExportAgent][google.cloud.dialogflow.v2beta1.Agents.ExportAgent]. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflow_v2beta1/services/answer_records/async_client.py b/google/cloud/dialogflow_v2beta1/services/answer_records/async_client.py index fd891a0a0..3f8bebb63 100644 --- a/google/cloud/dialogflow_v2beta1/services/answer_records/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/answer_records/async_client.py @@ -300,11 +300,12 @@ async def sample_get_answer_record(): the answers, [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] are returned to the customers. + 2. The customer uses the - [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] - to call the [UpdateAnswerRecord][] method to send - feedback about a specific answer that they believe - is wrong. + [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] + to call the [UpdateAnswerRecord][] method to send + feedback about a specific answer that they believe is + wrong. """ warnings.warn( @@ -399,7 +400,7 @@ async def sample_list_answer_records(): Returns: google.cloud.dialogflow_v2beta1.services.answer_records.pagers.ListAnswerRecordsAsyncPager: Response message for - [AnswerRecords.ListAnswerRecords][google.cloud.dialogflow.v2beta1.AnswerRecords.ListAnswerRecords]. + [AnswerRecords.ListAnswerRecords][google.cloud.dialogflow.v2beta1.AnswerRecords.ListAnswerRecords]. Iterating over this object will yield results and resolve additional pages automatically. @@ -547,11 +548,12 @@ async def sample_update_answer_record(): the answers, [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] are returned to the customers. + 2. The customer uses the - [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] - to call the [UpdateAnswerRecord][] method to send - feedback about a specific answer that they believe - is wrong. + [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] + to call the [UpdateAnswerRecord][] method to send + feedback about a specific answer that they believe is + wrong. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflow_v2beta1/services/answer_records/client.py b/google/cloud/dialogflow_v2beta1/services/answer_records/client.py index 6c95cf460..ca5019b0a 100644 --- a/google/cloud/dialogflow_v2beta1/services/answer_records/client.py +++ b/google/cloud/dialogflow_v2beta1/services/answer_records/client.py @@ -520,11 +520,12 @@ def sample_get_answer_record(): the answers, [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] are returned to the customers. + 2. The customer uses the - [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] - to call the [UpdateAnswerRecord][] method to send - feedback about a specific answer that they believe - is wrong. + [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] + to call the [UpdateAnswerRecord][] method to send + feedback about a specific answer that they believe is + wrong. """ warnings.warn( @@ -619,7 +620,7 @@ def sample_list_answer_records(): Returns: google.cloud.dialogflow_v2beta1.services.answer_records.pagers.ListAnswerRecordsPager: Response message for - [AnswerRecords.ListAnswerRecords][google.cloud.dialogflow.v2beta1.AnswerRecords.ListAnswerRecords]. + [AnswerRecords.ListAnswerRecords][google.cloud.dialogflow.v2beta1.AnswerRecords.ListAnswerRecords]. Iterating over this object will yield results and resolve additional pages automatically. @@ -767,11 +768,12 @@ def sample_update_answer_record(): the answers, [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] are returned to the customers. + 2. The customer uses the - [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] - to call the [UpdateAnswerRecord][] method to send - feedback about a specific answer that they believe - is wrong. + [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] + to call the [UpdateAnswerRecord][] method to send + feedback about a specific answer that they believe is + wrong. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflow_v2beta1/services/contexts/async_client.py b/google/cloud/dialogflow_v2beta1/services/contexts/async_client.py index 87d7697b8..eec5d45bd 100644 --- a/google/cloud/dialogflow_v2beta1/services/contexts/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/contexts/async_client.py @@ -283,7 +283,7 @@ async def sample_list_contexts(): Returns: google.cloud.dialogflow_v2beta1.services.contexts.pagers.ListContextsAsyncPager: The response message for - [Contexts.ListContexts][google.cloud.dialogflow.v2beta1.Contexts.ListContexts]. + [Contexts.ListContexts][google.cloud.dialogflow.v2beta1.Contexts.ListContexts]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/google/cloud/dialogflow_v2beta1/services/contexts/client.py b/google/cloud/dialogflow_v2beta1/services/contexts/client.py index 18f57988d..f6ab75791 100644 --- a/google/cloud/dialogflow_v2beta1/services/contexts/client.py +++ b/google/cloud/dialogflow_v2beta1/services/contexts/client.py @@ -516,7 +516,7 @@ def sample_list_contexts(): Returns: google.cloud.dialogflow_v2beta1.services.contexts.pagers.ListContextsPager: The response message for - [Contexts.ListContexts][google.cloud.dialogflow.v2beta1.Contexts.ListContexts]. + [Contexts.ListContexts][google.cloud.dialogflow.v2beta1.Contexts.ListContexts]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/google/cloud/dialogflow_v2beta1/services/conversation_profiles/async_client.py b/google/cloud/dialogflow_v2beta1/services/conversation_profiles/async_client.py index e848b912b..58ed1b6ab 100644 --- a/google/cloud/dialogflow_v2beta1/services/conversation_profiles/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/conversation_profiles/async_client.py @@ -314,7 +314,7 @@ async def sample_list_conversation_profiles(): Returns: google.cloud.dialogflow_v2beta1.services.conversation_profiles.pagers.ListConversationProfilesAsyncPager: The response message for - [ConversationProfiles.ListConversationProfiles][google.cloud.dialogflow.v2beta1.ConversationProfiles.ListConversationProfiles]. + [ConversationProfiles.ListConversationProfiles][google.cloud.dialogflow.v2beta1.ConversationProfiles.ListConversationProfiles]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/google/cloud/dialogflow_v2beta1/services/conversation_profiles/client.py b/google/cloud/dialogflow_v2beta1/services/conversation_profiles/client.py index 2abeeb029..a5661f09e 100644 --- a/google/cloud/dialogflow_v2beta1/services/conversation_profiles/client.py +++ b/google/cloud/dialogflow_v2beta1/services/conversation_profiles/client.py @@ -614,7 +614,7 @@ def sample_list_conversation_profiles(): Returns: google.cloud.dialogflow_v2beta1.services.conversation_profiles.pagers.ListConversationProfilesPager: The response message for - [ConversationProfiles.ListConversationProfiles][google.cloud.dialogflow.v2beta1.ConversationProfiles.ListConversationProfiles]. + [ConversationProfiles.ListConversationProfiles][google.cloud.dialogflow.v2beta1.ConversationProfiles.ListConversationProfiles]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/google/cloud/dialogflow_v2beta1/services/conversations/async_client.py b/google/cloud/dialogflow_v2beta1/services/conversations/async_client.py index 17e7b2e37..63052482e 100644 --- a/google/cloud/dialogflow_v2beta1/services/conversations/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/conversations/async_client.py @@ -436,7 +436,7 @@ async def sample_list_conversations(): Returns: google.cloud.dialogflow_v2beta1.services.conversations.pagers.ListConversationsAsyncPager: The response message for - [Conversations.ListConversations][google.cloud.dialogflow.v2beta1.Conversations.ListConversations]. + [Conversations.ListConversations][google.cloud.dialogflow.v2beta1.Conversations.ListConversations]. Iterating over this object will yield results and resolve additional pages automatically. @@ -883,7 +883,7 @@ async def sample_list_messages(): Returns: google.cloud.dialogflow_v2beta1.services.conversations.pagers.ListMessagesAsyncPager: The response message for - [Conversations.ListMessages][google.cloud.dialogflow.v2beta1.Conversations.ListMessages]. + [Conversations.ListMessages][google.cloud.dialogflow.v2beta1.Conversations.ListMessages]. Iterating over this object will yield results and resolve additional pages automatically. @@ -1002,7 +1002,7 @@ async def sample_suggest_conversation_summary(): Returns: google.cloud.dialogflow_v2beta1.types.SuggestConversationSummaryResponse: The response message for - [Conversations.SuggestConversationSummary][google.cloud.dialogflow.v2beta1.Conversations.SuggestConversationSummary]. + [Conversations.SuggestConversationSummary][google.cloud.dialogflow.v2beta1.Conversations.SuggestConversationSummary]. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflow_v2beta1/services/conversations/client.py b/google/cloud/dialogflow_v2beta1/services/conversations/client.py index 48f23c7e2..315e37252 100644 --- a/google/cloud/dialogflow_v2beta1/services/conversations/client.py +++ b/google/cloud/dialogflow_v2beta1/services/conversations/client.py @@ -709,7 +709,7 @@ def sample_list_conversations(): Returns: google.cloud.dialogflow_v2beta1.services.conversations.pagers.ListConversationsPager: The response message for - [Conversations.ListConversations][google.cloud.dialogflow.v2beta1.Conversations.ListConversations]. + [Conversations.ListConversations][google.cloud.dialogflow.v2beta1.Conversations.ListConversations]. Iterating over this object will yield results and resolve additional pages automatically. @@ -1156,7 +1156,7 @@ def sample_list_messages(): Returns: google.cloud.dialogflow_v2beta1.services.conversations.pagers.ListMessagesPager: The response message for - [Conversations.ListMessages][google.cloud.dialogflow.v2beta1.Conversations.ListMessages]. + [Conversations.ListMessages][google.cloud.dialogflow.v2beta1.Conversations.ListMessages]. Iterating over this object will yield results and resolve additional pages automatically. @@ -1275,7 +1275,7 @@ def sample_suggest_conversation_summary(): Returns: google.cloud.dialogflow_v2beta1.types.SuggestConversationSummaryResponse: The response message for - [Conversations.SuggestConversationSummary][google.cloud.dialogflow.v2beta1.Conversations.SuggestConversationSummary]. + [Conversations.SuggestConversationSummary][google.cloud.dialogflow.v2beta1.Conversations.SuggestConversationSummary]. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflow_v2beta1/services/documents/async_client.py b/google/cloud/dialogflow_v2beta1/services/documents/async_client.py index 0e08fbc21..85ec2ff04 100644 --- a/google/cloud/dialogflow_v2beta1/services/documents/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/documents/async_client.py @@ -281,7 +281,7 @@ async def sample_list_documents(): Returns: google.cloud.dialogflow_v2beta1.services.documents.pagers.ListDocumentsAsyncPager: Response message for - [Documents.ListDocuments][google.cloud.dialogflow.v2beta1.Documents.ListDocuments]. + [Documents.ListDocuments][google.cloud.dialogflow.v2beta1.Documents.ListDocuments]. Iterating over this object will yield results and resolve additional pages automatically. @@ -398,7 +398,7 @@ async def sample_get_document(): Returns: google.cloud.dialogflow_v2beta1.types.Document: A knowledge document to be used by a - [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. + [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. For more information, see the [knowledge base guide](\ https://cloud.google.com/dialogflow/docs/how/knowledge-bases). @@ -539,10 +539,8 @@ async def sample_create_document(): google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.Document` - A knowledge document to be used by a - [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.Document` A knowledge document to be used by a + [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. For more information, see the [knowledge base guide](\ https://cloud.google.com/dialogflow/docs/how/knowledge-bases). @@ -679,10 +677,8 @@ async def sample_import_documents(): google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.ImportDocumentsResponse` - Response message for - [Documents.ImportDocuments][google.cloud.dialogflow.v2beta1.Documents.ImportDocuments]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.ImportDocumentsResponse` Response message for + [Documents.ImportDocuments][google.cloud.dialogflow.v2beta1.Documents.ImportDocuments]. """ # Create or coerce a protobuf request object. @@ -946,10 +942,8 @@ async def sample_update_document(): google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.Document` - A knowledge document to be used by a - [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.Document` A knowledge document to be used by a + [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. For more information, see the [knowledge base guide](\ https://cloud.google.com/dialogflow/docs/how/knowledge-bases). @@ -1106,10 +1100,8 @@ async def sample_reload_document(): google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.Document` - A knowledge document to be used by a - [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.Document` A knowledge document to be used by a + [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. For more information, see the [knowledge base guide](\ https://cloud.google.com/dialogflow/docs/how/knowledge-bases). diff --git a/google/cloud/dialogflow_v2beta1/services/documents/client.py b/google/cloud/dialogflow_v2beta1/services/documents/client.py index f766b842c..741d0d47e 100644 --- a/google/cloud/dialogflow_v2beta1/services/documents/client.py +++ b/google/cloud/dialogflow_v2beta1/services/documents/client.py @@ -512,7 +512,7 @@ def sample_list_documents(): Returns: google.cloud.dialogflow_v2beta1.services.documents.pagers.ListDocumentsPager: Response message for - [Documents.ListDocuments][google.cloud.dialogflow.v2beta1.Documents.ListDocuments]. + [Documents.ListDocuments][google.cloud.dialogflow.v2beta1.Documents.ListDocuments]. Iterating over this object will yield results and resolve additional pages automatically. @@ -629,7 +629,7 @@ def sample_get_document(): Returns: google.cloud.dialogflow_v2beta1.types.Document: A knowledge document to be used by a - [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. + [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. For more information, see the [knowledge base guide](\ https://cloud.google.com/dialogflow/docs/how/knowledge-bases). @@ -770,10 +770,8 @@ def sample_create_document(): google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.Document` - A knowledge document to be used by a - [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.Document` A knowledge document to be used by a + [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. For more information, see the [knowledge base guide](\ https://cloud.google.com/dialogflow/docs/how/knowledge-bases). @@ -910,10 +908,8 @@ def sample_import_documents(): google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.ImportDocumentsResponse` - Response message for - [Documents.ImportDocuments][google.cloud.dialogflow.v2beta1.Documents.ImportDocuments]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.ImportDocumentsResponse` Response message for + [Documents.ImportDocuments][google.cloud.dialogflow.v2beta1.Documents.ImportDocuments]. """ # Create or coerce a protobuf request object. @@ -1178,10 +1174,8 @@ def sample_update_document(): google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.Document` - A knowledge document to be used by a - [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.Document` A knowledge document to be used by a + [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. For more information, see the [knowledge base guide](\ https://cloud.google.com/dialogflow/docs/how/knowledge-bases). @@ -1338,10 +1332,8 @@ def sample_reload_document(): google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.Document` - A knowledge document to be used by a - [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.Document` A knowledge document to be used by a + [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. For more information, see the [knowledge base guide](\ https://cloud.google.com/dialogflow/docs/how/knowledge-bases). diff --git a/google/cloud/dialogflow_v2beta1/services/entity_types/async_client.py b/google/cloud/dialogflow_v2beta1/services/entity_types/async_client.py index 8a31d9983..b6deda206 100644 --- a/google/cloud/dialogflow_v2beta1/services/entity_types/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/entity_types/async_client.py @@ -294,7 +294,7 @@ async def sample_list_entity_types(): Returns: google.cloud.dialogflow_v2beta1.services.entity_types.pagers.ListEntityTypesAsyncPager: The response message for - [EntityTypes.ListEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.ListEntityTypes]. + [EntityTypes.ListEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.ListEntityTypes]. Iterating over this object will yield results and resolve additional pages automatically. @@ -946,10 +946,8 @@ async def sample_batch_update_entity_types(): google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.BatchUpdateEntityTypesResponse` - The response message for - [EntityTypes.BatchUpdateEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.BatchUpdateEntityTypes]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.BatchUpdateEntityTypesResponse` The response message for + [EntityTypes.BatchUpdateEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.BatchUpdateEntityTypes]. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflow_v2beta1/services/entity_types/client.py b/google/cloud/dialogflow_v2beta1/services/entity_types/client.py index 358f513df..fef0646c9 100644 --- a/google/cloud/dialogflow_v2beta1/services/entity_types/client.py +++ b/google/cloud/dialogflow_v2beta1/services/entity_types/client.py @@ -520,7 +520,7 @@ def sample_list_entity_types(): Returns: google.cloud.dialogflow_v2beta1.services.entity_types.pagers.ListEntityTypesPager: The response message for - [EntityTypes.ListEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.ListEntityTypes]. + [EntityTypes.ListEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.ListEntityTypes]. Iterating over this object will yield results and resolve additional pages automatically. @@ -1172,10 +1172,8 @@ def sample_batch_update_entity_types(): google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.BatchUpdateEntityTypesResponse` - The response message for - [EntityTypes.BatchUpdateEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.BatchUpdateEntityTypes]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.BatchUpdateEntityTypesResponse` The response message for + [EntityTypes.BatchUpdateEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.BatchUpdateEntityTypes]. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflow_v2beta1/services/environments/async_client.py b/google/cloud/dialogflow_v2beta1/services/environments/async_client.py index d893008ac..da92e730f 100644 --- a/google/cloud/dialogflow_v2beta1/services/environments/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/environments/async_client.py @@ -282,7 +282,7 @@ async def sample_list_environments(): Returns: google.cloud.dialogflow_v2beta1.services.environments.pagers.ListEnvironmentsAsyncPager: The response message for - [Environments.ListEnvironments][google.cloud.dialogflow.v2beta1.Environments.ListEnvironments]. + [Environments.ListEnvironments][google.cloud.dialogflow.v2beta1.Environments.ListEnvironments]. Iterating over this object will yield results and resolve additional pages automatically. @@ -768,7 +768,7 @@ async def sample_get_environment_history(): Returns: google.cloud.dialogflow_v2beta1.services.environments.pagers.GetEnvironmentHistoryAsyncPager: The response message for - [Environments.GetEnvironmentHistory][google.cloud.dialogflow.v2beta1.Environments.GetEnvironmentHistory]. + [Environments.GetEnvironmentHistory][google.cloud.dialogflow.v2beta1.Environments.GetEnvironmentHistory]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/google/cloud/dialogflow_v2beta1/services/environments/client.py b/google/cloud/dialogflow_v2beta1/services/environments/client.py index 4494729ca..5044d3518 100644 --- a/google/cloud/dialogflow_v2beta1/services/environments/client.py +++ b/google/cloud/dialogflow_v2beta1/services/environments/client.py @@ -538,7 +538,7 @@ def sample_list_environments(): Returns: google.cloud.dialogflow_v2beta1.services.environments.pagers.ListEnvironmentsPager: The response message for - [Environments.ListEnvironments][google.cloud.dialogflow.v2beta1.Environments.ListEnvironments]. + [Environments.ListEnvironments][google.cloud.dialogflow.v2beta1.Environments.ListEnvironments]. Iterating over this object will yield results and resolve additional pages automatically. @@ -1028,7 +1028,7 @@ def sample_get_environment_history(): Returns: google.cloud.dialogflow_v2beta1.services.environments.pagers.GetEnvironmentHistoryPager: The response message for - [Environments.GetEnvironmentHistory][google.cloud.dialogflow.v2beta1.Environments.GetEnvironmentHistory]. + [Environments.GetEnvironmentHistory][google.cloud.dialogflow.v2beta1.Environments.GetEnvironmentHistory]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/google/cloud/dialogflow_v2beta1/services/intents/async_client.py b/google/cloud/dialogflow_v2beta1/services/intents/async_client.py index e9e8db424..bced878c5 100644 --- a/google/cloud/dialogflow_v2beta1/services/intents/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/intents/async_client.py @@ -299,7 +299,7 @@ async def sample_list_intents(): Returns: google.cloud.dialogflow_v2beta1.services.intents.pagers.ListIntentsAsyncPager: The response message for - [Intents.ListIntents][google.cloud.dialogflow.v2beta1.Intents.ListIntents]. + [Intents.ListIntents][google.cloud.dialogflow.v2beta1.Intents.ListIntents]. Iterating over this object will yield results and resolve additional pages automatically. @@ -969,10 +969,8 @@ async def sample_batch_update_intents(): google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.BatchUpdateIntentsResponse` - The response message for - [Intents.BatchUpdateIntents][google.cloud.dialogflow.v2beta1.Intents.BatchUpdateIntents]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.BatchUpdateIntentsResponse` The response message for + [Intents.BatchUpdateIntents][google.cloud.dialogflow.v2beta1.Intents.BatchUpdateIntents]. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflow_v2beta1/services/intents/client.py b/google/cloud/dialogflow_v2beta1/services/intents/client.py index b981ccf71..771cabead 100644 --- a/google/cloud/dialogflow_v2beta1/services/intents/client.py +++ b/google/cloud/dialogflow_v2beta1/services/intents/client.py @@ -547,7 +547,7 @@ def sample_list_intents(): Returns: google.cloud.dialogflow_v2beta1.services.intents.pagers.ListIntentsPager: The response message for - [Intents.ListIntents][google.cloud.dialogflow.v2beta1.Intents.ListIntents]. + [Intents.ListIntents][google.cloud.dialogflow.v2beta1.Intents.ListIntents]. Iterating over this object will yield results and resolve additional pages automatically. @@ -1217,10 +1217,8 @@ def sample_batch_update_intents(): google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:`google.cloud.dialogflow_v2beta1.types.BatchUpdateIntentsResponse` - The response message for - [Intents.BatchUpdateIntents][google.cloud.dialogflow.v2beta1.Intents.BatchUpdateIntents]. + The result type for the operation will be :class:`google.cloud.dialogflow_v2beta1.types.BatchUpdateIntentsResponse` The response message for + [Intents.BatchUpdateIntents][google.cloud.dialogflow.v2beta1.Intents.BatchUpdateIntents]. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflow_v2beta1/services/knowledge_bases/async_client.py b/google/cloud/dialogflow_v2beta1/services/knowledge_bases/async_client.py index 67341f5d7..7f01250cb 100644 --- a/google/cloud/dialogflow_v2beta1/services/knowledge_bases/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/knowledge_bases/async_client.py @@ -285,7 +285,7 @@ async def sample_list_knowledge_bases(): Returns: google.cloud.dialogflow_v2beta1.services.knowledge_bases.pagers.ListKnowledgeBasesAsyncPager: Response message for - [KnowledgeBases.ListKnowledgeBases][google.cloud.dialogflow.v2beta1.KnowledgeBases.ListKnowledgeBases]. + [KnowledgeBases.ListKnowledgeBases][google.cloud.dialogflow.v2beta1.KnowledgeBases.ListKnowledgeBases]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/google/cloud/dialogflow_v2beta1/services/knowledge_bases/client.py b/google/cloud/dialogflow_v2beta1/services/knowledge_bases/client.py index 2125807b2..b90ba932e 100644 --- a/google/cloud/dialogflow_v2beta1/services/knowledge_bases/client.py +++ b/google/cloud/dialogflow_v2beta1/services/knowledge_bases/client.py @@ -507,7 +507,7 @@ def sample_list_knowledge_bases(): Returns: google.cloud.dialogflow_v2beta1.services.knowledge_bases.pagers.ListKnowledgeBasesPager: Response message for - [KnowledgeBases.ListKnowledgeBases][google.cloud.dialogflow.v2beta1.KnowledgeBases.ListKnowledgeBases]. + [KnowledgeBases.ListKnowledgeBases][google.cloud.dialogflow.v2beta1.KnowledgeBases.ListKnowledgeBases]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/google/cloud/dialogflow_v2beta1/services/participants/async_client.py b/google/cloud/dialogflow_v2beta1/services/participants/async_client.py index 5c095fddc..5475ffda3 100644 --- a/google/cloud/dialogflow_v2beta1/services/participants/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/participants/async_client.py @@ -509,7 +509,7 @@ async def sample_list_participants(): Returns: google.cloud.dialogflow_v2beta1.services.participants.pagers.ListParticipantsAsyncPager: The response message for - [Participants.ListParticipants][google.cloud.dialogflow.v2beta1.Participants.ListParticipants]. + [Participants.ListParticipants][google.cloud.dialogflow.v2beta1.Participants.ListParticipants]. Iterating over this object will yield results and resolve additional pages automatically. @@ -762,7 +762,7 @@ async def sample_analyze_content(): Returns: google.cloud.dialogflow_v2beta1.types.AnalyzeContentResponse: The response message for - [Participants.AnalyzeContent][google.cloud.dialogflow.v2beta1.Participants.AnalyzeContent]. + [Participants.AnalyzeContent][google.cloud.dialogflow.v2beta1.Participants.AnalyzeContent]. """ # Create or coerce a protobuf request object. @@ -894,6 +894,7 @@ def request_generator(): client to the [Participants.StreamingAnalyzeContent][google.cloud.dialogflow.v2beta1.Participants.StreamingAnalyzeContent] method. + Multiple request messages should be sent in order: 1. The first message must contain @@ -901,21 +902,21 @@ def request_generator(): [config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.config] and optionally [query_params][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.query_params]. - If you want to receive an audio response, it should - also contain + If you want to receive an audio response, it should also + contain [reply_audio_config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.reply_audio_config]. The message must not contain [input][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.input]. 2. If [config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.config] - in the first message was set to + in the first message + was set to [audio_config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.audio_config], all subsequent messages must contain [input_audio][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.input_audio] - to continue with Speech recognition. - If you decide to rather analyze text input after you - already started Speech recognition, please send a - message with + to continue with Speech recognition. If you decide to + rather analyze text input after you already started + Speech recognition, please send a message with [StreamingAnalyzeContentRequest.input_text][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.input_text]. However, note that: @@ -925,9 +926,10 @@ def request_generator(): 3. If [StreamingAnalyzeContentRequest.config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.config] - in the first message was set to + in the first message was set + to [StreamingAnalyzeContentRequest.text_config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.text_config], - then the second message must contain only + then the second message must contain only [input_text][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.input_text]. Moreover, you must not send more than two messages. After you sent all input, you must half-close or abort @@ -1054,7 +1056,7 @@ async def sample_suggest_articles(): Returns: google.cloud.dialogflow_v2beta1.types.SuggestArticlesResponse: The response message for - [Participants.SuggestArticles][google.cloud.dialogflow.v2beta1.Participants.SuggestArticles]. + [Participants.SuggestArticles][google.cloud.dialogflow.v2beta1.Participants.SuggestArticles]. """ # Create or coerce a protobuf request object. @@ -1158,7 +1160,7 @@ async def sample_suggest_faq_answers(): Returns: google.cloud.dialogflow_v2beta1.types.SuggestFaqAnswersResponse: The request message for - [Participants.SuggestFaqAnswers][google.cloud.dialogflow.v2beta1.Participants.SuggestFaqAnswers]. + [Participants.SuggestFaqAnswers][google.cloud.dialogflow.v2beta1.Participants.SuggestFaqAnswers]. """ # Create or coerce a protobuf request object. @@ -1262,7 +1264,7 @@ async def sample_suggest_smart_replies(): Returns: google.cloud.dialogflow_v2beta1.types.SuggestSmartRepliesResponse: The response message for - [Participants.SuggestSmartReplies][google.cloud.dialogflow.v2beta1.Participants.SuggestSmartReplies]. + [Participants.SuggestSmartReplies][google.cloud.dialogflow.v2beta1.Participants.SuggestSmartReplies]. """ # Create or coerce a protobuf request object. @@ -1375,7 +1377,7 @@ async def sample_list_suggestions(): Returns: google.cloud.dialogflow_v2beta1.services.participants.pagers.ListSuggestionsAsyncPager: The response message for - [Participants.ListSuggestions][google.cloud.dialogflow.v2beta1.Participants.ListSuggestions]. + [Participants.ListSuggestions][google.cloud.dialogflow.v2beta1.Participants.ListSuggestions]. Iterating over this object will yield results and resolve additional pages automatically. @@ -1484,7 +1486,7 @@ async def sample_compile_suggestion(): Returns: google.cloud.dialogflow_v2beta1.types.CompileSuggestionResponse: The response message for - [Participants.CompileSuggestion][google.cloud.dialogflow.v2beta1.Participants.CompileSuggestion]. + [Participants.CompileSuggestion][google.cloud.dialogflow.v2beta1.Participants.CompileSuggestion]. """ warnings.warn( diff --git a/google/cloud/dialogflow_v2beta1/services/participants/client.py b/google/cloud/dialogflow_v2beta1/services/participants/client.py index 8702009fb..cf15ee264 100644 --- a/google/cloud/dialogflow_v2beta1/services/participants/client.py +++ b/google/cloud/dialogflow_v2beta1/services/participants/client.py @@ -849,7 +849,7 @@ def sample_list_participants(): Returns: google.cloud.dialogflow_v2beta1.services.participants.pagers.ListParticipantsPager: The response message for - [Participants.ListParticipants][google.cloud.dialogflow.v2beta1.Participants.ListParticipants]. + [Participants.ListParticipants][google.cloud.dialogflow.v2beta1.Participants.ListParticipants]. Iterating over this object will yield results and resolve additional pages automatically. @@ -1102,7 +1102,7 @@ def sample_analyze_content(): Returns: google.cloud.dialogflow_v2beta1.types.AnalyzeContentResponse: The response message for - [Participants.AnalyzeContent][google.cloud.dialogflow.v2beta1.Participants.AnalyzeContent]. + [Participants.AnalyzeContent][google.cloud.dialogflow.v2beta1.Participants.AnalyzeContent]. """ # Create or coerce a protobuf request object. @@ -1223,6 +1223,7 @@ def request_generator(): client to the [Participants.StreamingAnalyzeContent][google.cloud.dialogflow.v2beta1.Participants.StreamingAnalyzeContent] method. + Multiple request messages should be sent in order: 1. The first message must contain @@ -1230,21 +1231,21 @@ def request_generator(): [config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.config] and optionally [query_params][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.query_params]. - If you want to receive an audio response, it should - also contain + If you want to receive an audio response, it should also + contain [reply_audio_config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.reply_audio_config]. The message must not contain [input][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.input]. 2. If [config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.config] - in the first message was set to + in the first message + was set to [audio_config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.audio_config], all subsequent messages must contain [input_audio][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.input_audio] - to continue with Speech recognition. - If you decide to rather analyze text input after you - already started Speech recognition, please send a - message with + to continue with Speech recognition. If you decide to + rather analyze text input after you already started + Speech recognition, please send a message with [StreamingAnalyzeContentRequest.input_text][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.input_text]. However, note that: @@ -1254,9 +1255,10 @@ def request_generator(): 3. If [StreamingAnalyzeContentRequest.config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.config] - in the first message was set to + in the first message was set + to [StreamingAnalyzeContentRequest.text_config][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.text_config], - then the second message must contain only + then the second message must contain only [input_text][google.cloud.dialogflow.v2beta1.StreamingAnalyzeContentRequest.input_text]. Moreover, you must not send more than two messages. After you sent all input, you must half-close or abort @@ -1381,7 +1383,7 @@ def sample_suggest_articles(): Returns: google.cloud.dialogflow_v2beta1.types.SuggestArticlesResponse: The response message for - [Participants.SuggestArticles][google.cloud.dialogflow.v2beta1.Participants.SuggestArticles]. + [Participants.SuggestArticles][google.cloud.dialogflow.v2beta1.Participants.SuggestArticles]. """ # Create or coerce a protobuf request object. @@ -1485,7 +1487,7 @@ def sample_suggest_faq_answers(): Returns: google.cloud.dialogflow_v2beta1.types.SuggestFaqAnswersResponse: The request message for - [Participants.SuggestFaqAnswers][google.cloud.dialogflow.v2beta1.Participants.SuggestFaqAnswers]. + [Participants.SuggestFaqAnswers][google.cloud.dialogflow.v2beta1.Participants.SuggestFaqAnswers]. """ # Create or coerce a protobuf request object. @@ -1589,7 +1591,7 @@ def sample_suggest_smart_replies(): Returns: google.cloud.dialogflow_v2beta1.types.SuggestSmartRepliesResponse: The response message for - [Participants.SuggestSmartReplies][google.cloud.dialogflow.v2beta1.Participants.SuggestSmartReplies]. + [Participants.SuggestSmartReplies][google.cloud.dialogflow.v2beta1.Participants.SuggestSmartReplies]. """ # Create or coerce a protobuf request object. @@ -1702,7 +1704,7 @@ def sample_list_suggestions(): Returns: google.cloud.dialogflow_v2beta1.services.participants.pagers.ListSuggestionsPager: The response message for - [Participants.ListSuggestions][google.cloud.dialogflow.v2beta1.Participants.ListSuggestions]. + [Participants.ListSuggestions][google.cloud.dialogflow.v2beta1.Participants.ListSuggestions]. Iterating over this object will yield results and resolve additional pages automatically. @@ -1812,7 +1814,7 @@ def sample_compile_suggestion(): Returns: google.cloud.dialogflow_v2beta1.types.CompileSuggestionResponse: The response message for - [Participants.CompileSuggestion][google.cloud.dialogflow.v2beta1.Participants.CompileSuggestion]. + [Participants.CompileSuggestion][google.cloud.dialogflow.v2beta1.Participants.CompileSuggestion]. """ warnings.warn( diff --git a/google/cloud/dialogflow_v2beta1/services/session_entity_types/async_client.py b/google/cloud/dialogflow_v2beta1/services/session_entity_types/async_client.py index b31a2ba1c..780f79051 100644 --- a/google/cloud/dialogflow_v2beta1/services/session_entity_types/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/session_entity_types/async_client.py @@ -303,7 +303,7 @@ async def sample_list_session_entity_types(): Returns: google.cloud.dialogflow_v2beta1.services.session_entity_types.pagers.ListSessionEntityTypesAsyncPager: The response message for - [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.v2beta1.SessionEntityTypes.ListSessionEntityTypes]. + [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.v2beta1.SessionEntityTypes.ListSessionEntityTypes]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/google/cloud/dialogflow_v2beta1/services/session_entity_types/client.py b/google/cloud/dialogflow_v2beta1/services/session_entity_types/client.py index 95e3b53f0..bb55d2739 100644 --- a/google/cloud/dialogflow_v2beta1/services/session_entity_types/client.py +++ b/google/cloud/dialogflow_v2beta1/services/session_entity_types/client.py @@ -525,7 +525,7 @@ def sample_list_session_entity_types(): Returns: google.cloud.dialogflow_v2beta1.services.session_entity_types.pagers.ListSessionEntityTypesPager: The response message for - [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.v2beta1.SessionEntityTypes.ListSessionEntityTypes]. + [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.v2beta1.SessionEntityTypes.ListSessionEntityTypes]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/google/cloud/dialogflow_v2beta1/services/sessions/async_client.py b/google/cloud/dialogflow_v2beta1/services/sessions/async_client.py index e1186d3ee..479c6d820 100644 --- a/google/cloud/dialogflow_v2beta1/services/sessions/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/sessions/async_client.py @@ -461,6 +461,7 @@ def request_generator(): client to the [Sessions.StreamingDetectIntent][google.cloud.dialogflow.v2beta1.Sessions.StreamingDetectIntent] method. + Multiple request messages should be sent in order: 1. The first message must contain @@ -468,7 +469,7 @@ def request_generator(): [query_input][google.cloud.dialogflow.v2beta1.StreamingDetectIntentRequest.query_input] plus optionally [query_params][google.cloud.dialogflow.v2beta1.StreamingDetectIntentRequest.query_params]. - If the client wants to receive an audio response, it + If the client wants to receive an audio response, it should also contain [output_audio_config][google.cloud.dialogflow.v2beta1.StreamingDetectIntentRequest.output_audio_config]. The message must not contain @@ -477,12 +478,12 @@ def request_generator(): [query_input][google.cloud.dialogflow.v2beta1.StreamingDetectIntentRequest.query_input] was set to [query_input.audio_config][google.cloud.dialogflow.v2beta1.InputAudioConfig], - all subsequent messages must contain + all subsequent messages must contain [input_audio][google.cloud.dialogflow.v2beta1.StreamingDetectIntentRequest.input_audio] - to continue with Speech recognition. - If you decide to rather detect an intent from text - input after you already started Speech recognition, - please send a message with + to continue with Speech recognition. If you decide to + rather detect an intent from text input after you + already started Speech recognition, please send a + message with [query_input.text][google.cloud.dialogflow.v2beta1.QueryInput.text]. However, note that: diff --git a/google/cloud/dialogflow_v2beta1/services/sessions/client.py b/google/cloud/dialogflow_v2beta1/services/sessions/client.py index 7d62ff21f..705ec8e89 100644 --- a/google/cloud/dialogflow_v2beta1/services/sessions/client.py +++ b/google/cloud/dialogflow_v2beta1/services/sessions/client.py @@ -754,6 +754,7 @@ def request_generator(): client to the [Sessions.StreamingDetectIntent][google.cloud.dialogflow.v2beta1.Sessions.StreamingDetectIntent] method. + Multiple request messages should be sent in order: 1. The first message must contain @@ -761,7 +762,7 @@ def request_generator(): [query_input][google.cloud.dialogflow.v2beta1.StreamingDetectIntentRequest.query_input] plus optionally [query_params][google.cloud.dialogflow.v2beta1.StreamingDetectIntentRequest.query_params]. - If the client wants to receive an audio response, it + If the client wants to receive an audio response, it should also contain [output_audio_config][google.cloud.dialogflow.v2beta1.StreamingDetectIntentRequest.output_audio_config]. The message must not contain @@ -770,12 +771,12 @@ def request_generator(): [query_input][google.cloud.dialogflow.v2beta1.StreamingDetectIntentRequest.query_input] was set to [query_input.audio_config][google.cloud.dialogflow.v2beta1.InputAudioConfig], - all subsequent messages must contain + all subsequent messages must contain [input_audio][google.cloud.dialogflow.v2beta1.StreamingDetectIntentRequest.input_audio] - to continue with Speech recognition. - If you decide to rather detect an intent from text - input after you already started Speech recognition, - please send a message with + to continue with Speech recognition. If you decide to + rather detect an intent from text input after you + already started Speech recognition, please send a + message with [query_input.text][google.cloud.dialogflow.v2beta1.QueryInput.text]. However, note that: diff --git a/google/cloud/dialogflow_v2beta1/services/versions/async_client.py b/google/cloud/dialogflow_v2beta1/services/versions/async_client.py index 1ab49ba5a..91abdc3d6 100644 --- a/google/cloud/dialogflow_v2beta1/services/versions/async_client.py +++ b/google/cloud/dialogflow_v2beta1/services/versions/async_client.py @@ -276,7 +276,7 @@ async def sample_list_versions(): Returns: google.cloud.dialogflow_v2beta1.services.versions.pagers.ListVersionsAsyncPager: The response message for - [Versions.ListVersions][google.cloud.dialogflow.v2beta1.Versions.ListVersions]. + [Versions.ListVersions][google.cloud.dialogflow.v2beta1.Versions.ListVersions]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/google/cloud/dialogflow_v2beta1/services/versions/client.py b/google/cloud/dialogflow_v2beta1/services/versions/client.py index 8c2816ada..c3e26a0a1 100644 --- a/google/cloud/dialogflow_v2beta1/services/versions/client.py +++ b/google/cloud/dialogflow_v2beta1/services/versions/client.py @@ -506,7 +506,7 @@ def sample_list_versions(): Returns: google.cloud.dialogflow_v2beta1.services.versions.pagers.ListVersionsPager: The response message for - [Versions.ListVersions][google.cloud.dialogflow.v2beta1.Versions.ListVersions]. + [Versions.ListVersions][google.cloud.dialogflow.v2beta1.Versions.ListVersions]. Iterating over this object will yield results and resolve additional pages automatically. diff --git a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2.json b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2.json index 166985601..43eb1e2b9 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dialogflow", - "version": "2.19.1" + "version": "0.1.0" }, "snippets": [ { diff --git a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2beta1.json b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2beta1.json index 91c89375d..748920df0 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2beta1.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dialogflow", - "version": "2.19.1" + "version": "0.1.0" }, "snippets": [ { From c80ffbab9a962ab74d7ceab780b21e3f9df9606e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 24 Jan 2023 15:14:56 +0000 Subject: [PATCH 02/10] chore(deps): update dependency google-cloud-dialogflow to v2.19.1 (#613) Co-authored-by: Anthonios Partheniou --- samples/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index 9a2a040a5..d2a43254c 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,2 +1,2 @@ -google-cloud-dialogflow==2.19.0 +google-cloud-dialogflow==2.19.1 Flask==2.2.2 From bd2f50f59cc417c7fc1888002f6594bea74592c7 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Wed, 25 Jan 2023 11:33:50 -0500 Subject: [PATCH 03/10] chore: Update gapic-generator-python to v1.8.2 (#616) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: Update gapic-generator-python to v1.8.2 PiperOrigin-RevId: 504289125 Source-Link: https://github.com/googleapis/googleapis/commit/38a48a44a44279e9cf9f2f864b588958a2d87491 Source-Link: https://github.com/googleapis/googleapis-gen/commit/b2dc22663dbe47a972c8d8c2f8a4df013dafdcbc Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiYjJkYzIyNjYzZGJlNDdhOTcyYzhkOGMyZjhhNGRmMDEzZGFmZGNiYyJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot --- .coveragerc | 1 + google/cloud/dialogflow_v2/__init__.py | 2 +- google/cloud/dialogflow_v2beta1/__init__.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.coveragerc b/.coveragerc index d0da0459f..3e1752c7a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -5,6 +5,7 @@ branch = True show_missing = True omit = google/cloud/dialogflow/__init__.py + google/cloud/dialogflow/gapic_version.py exclude_lines = # Re-enable the standard pragma pragma: NO COVER diff --git a/google/cloud/dialogflow_v2/__init__.py b/google/cloud/dialogflow_v2/__init__.py index 43dde2333..2afbcb115 100644 --- a/google/cloud/dialogflow_v2/__init__.py +++ b/google/cloud/dialogflow_v2/__init__.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -from google.cloud.dialogflow import gapic_version as package_version +from google.cloud.dialogflow_v2 import gapic_version as package_version __version__ = package_version.__version__ diff --git a/google/cloud/dialogflow_v2beta1/__init__.py b/google/cloud/dialogflow_v2beta1/__init__.py index 9c2980ef0..10ea38e0c 100644 --- a/google/cloud/dialogflow_v2beta1/__init__.py +++ b/google/cloud/dialogflow_v2beta1/__init__.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -from google.cloud.dialogflow import gapic_version as package_version +from google.cloud.dialogflow_v2beta1 import gapic_version as package_version __version__ = package_version.__version__ From 876a7f11251fabd465f89ce1d84b75d3e83d2b65 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Mon, 30 Jan 2023 16:54:11 +0000 Subject: [PATCH 04/10] chore: fix prerelease_deps nox session [autoapprove] (#617) Source-Link: https://togithub.com/googleapis/synthtool/commit/26c7505b2f76981ec1707b851e1595c8c06e90fc Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:f946c75373c2b0040e8e318c5e85d0cf46bc6e61d0a01f3ef94d8de974ac6790 --- .github/.OwlBot.lock.yaml | 2 +- noxfile.py | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 889f77dfa..f0f3b24b2 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,4 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:c43f1d918bcf817d337aa29ff833439494a158a0831508fda4ec75dc4c0d0320 + digest: sha256:f946c75373c2b0040e8e318c5e85d0cf46bc6e61d0a01f3ef94d8de974ac6790 diff --git a/noxfile.py b/noxfile.py index f456ebd34..cea395415 100644 --- a/noxfile.py +++ b/noxfile.py @@ -189,9 +189,9 @@ def unit(session): def install_systemtest_dependencies(session, *constraints): # Use pre-release gRPC for system tests. - # Exclude version 1.49.0rc1 which has a known issue. - # See https://github.com/grpc/grpc/pull/30642 - session.install("--pre", "grpcio!=1.49.0rc1") + # Exclude version 1.52.0rc1 which has a known issue. + # See https://github.com/grpc/grpc/issues/32163 + session.install("--pre", "grpcio!=1.52.0rc1") session.install(*SYSTEM_TEST_STANDARD_DEPENDENCIES, *constraints) @@ -345,9 +345,7 @@ def prerelease_deps(session): unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES session.install(*unit_deps_all) system_deps_all = ( - SYSTEM_TEST_STANDARD_DEPENDENCIES - + SYSTEM_TEST_EXTERNAL_DEPENDENCIES - + SYSTEM_TEST_EXTRAS + SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES ) session.install(*system_deps_all) @@ -377,8 +375,8 @@ def prerelease_deps(session): # dependency of grpc "six", "googleapis-common-protos", - # Exclude version 1.49.0rc1 which has a known issue. See https://github.com/grpc/grpc/pull/30642 - "grpcio!=1.49.0rc1", + # Exclude version 1.52.0rc1 which has a known issue. See https://github.com/grpc/grpc/issues/32163 + "grpcio!=1.52.0rc1", "grpcio-status", "google-api-core", "proto-plus", From 4cee73a033975355ab8db6cf1936da59ed1a34f2 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Wed, 8 Feb 2023 07:07:46 -0500 Subject: [PATCH 05/10] chore: Update gapic-generator-python to v1.8.4 (#618) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: Update gapic-generator-python to v1.8.4 PiperOrigin-RevId: 507808936 Source-Link: https://github.com/googleapis/googleapis/commit/64cf8492b21778ce62c66ecee81b468a293bfd4c Source-Link: https://github.com/googleapis/googleapis-gen/commit/53c48cac153d3b37f3d2c2dec4830cfd91ec4153 Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiNTNjNDhjYWMxNTNkM2IzN2YzZDJjMmRlYzQ4MzBjZmQ5MWVjNDE1MyJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot --- setup.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 9f87a32f3..044759516 100644 --- a/setup.py +++ b/setup.py @@ -55,9 +55,7 @@ if package.startswith("google") ] -namespaces = ["google"] -if "google.cloud" in packages: - namespaces.append("google.cloud") +namespaces = ["google", "google.cloud"] setuptools.setup( name=name, From 7af51b300119147a23d396b5752aba8b6d06ddd2 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Wed, 8 Feb 2023 15:16:12 +0000 Subject: [PATCH 06/10] build(deps): bump cryptography from 38.0.3 to 39.0.1 in /synthtool/gcp/templates/python_library/.kokoro (#620) Source-Link: https://togithub.com/googleapis/synthtool/commit/bb171351c3946d3c3c32e60f5f18cee8c464ec51 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:f62c53736eccb0c4934a3ea9316e0d57696bb49c1a7c86c726e9bb8a2f87dadf --- .github/.OwlBot.lock.yaml | 2 +- .kokoro/requirements.txt | 49 ++++++++++++++++++--------------------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index f0f3b24b2..894fb6bc9 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,4 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:f946c75373c2b0040e8e318c5e85d0cf46bc6e61d0a01f3ef94d8de974ac6790 + digest: sha256:f62c53736eccb0c4934a3ea9316e0d57696bb49c1a7c86c726e9bb8a2f87dadf diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt index 05dc4672e..096e4800a 100644 --- a/.kokoro/requirements.txt +++ b/.kokoro/requirements.txt @@ -113,33 +113,28 @@ commonmark==0.9.1 \ --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 # via rich -cryptography==38.0.3 \ - --hash=sha256:068147f32fa662c81aebab95c74679b401b12b57494872886eb5c1139250ec5d \ - --hash=sha256:06fc3cc7b6f6cca87bd56ec80a580c88f1da5306f505876a71c8cfa7050257dd \ - --hash=sha256:25c1d1f19729fb09d42e06b4bf9895212292cb27bb50229f5aa64d039ab29146 \ - --hash=sha256:402852a0aea73833d982cabb6d0c3bb582c15483d29fb7085ef2c42bfa7e38d7 \ - --hash=sha256:4e269dcd9b102c5a3d72be3c45d8ce20377b8076a43cbed6f660a1afe365e436 \ - --hash=sha256:5419a127426084933076132d317911e3c6eb77568a1ce23c3ac1e12d111e61e0 \ - --hash=sha256:554bec92ee7d1e9d10ded2f7e92a5d70c1f74ba9524947c0ba0c850c7b011828 \ - --hash=sha256:5e89468fbd2fcd733b5899333bc54d0d06c80e04cd23d8c6f3e0542358c6060b \ - --hash=sha256:65535bc550b70bd6271984d9863a37741352b4aad6fb1b3344a54e6950249b55 \ - --hash=sha256:6ab9516b85bebe7aa83f309bacc5f44a61eeb90d0b4ec125d2d003ce41932d36 \ - --hash=sha256:6addc3b6d593cd980989261dc1cce38263c76954d758c3c94de51f1e010c9a50 \ - --hash=sha256:728f2694fa743a996d7784a6194da430f197d5c58e2f4e278612b359f455e4a2 \ - --hash=sha256:785e4056b5a8b28f05a533fab69febf5004458e20dad7e2e13a3120d8ecec75a \ - --hash=sha256:78cf5eefac2b52c10398a42765bfa981ce2372cbc0457e6bf9658f41ec3c41d8 \ - --hash=sha256:7f836217000342d448e1c9a342e9163149e45d5b5eca76a30e84503a5a96cab0 \ - --hash=sha256:8d41a46251bf0634e21fac50ffd643216ccecfaf3701a063257fe0b2be1b6548 \ - --hash=sha256:984fe150f350a3c91e84de405fe49e688aa6092b3525f407a18b9646f6612320 \ - --hash=sha256:9b24bcff7853ed18a63cfb0c2b008936a9554af24af2fb146e16d8e1aed75748 \ - --hash=sha256:b1b35d9d3a65542ed2e9d90115dfd16bbc027b3f07ee3304fc83580f26e43249 \ - --hash=sha256:b1b52c9e5f8aa2b802d48bd693190341fae201ea51c7a167d69fc48b60e8a959 \ - --hash=sha256:bbf203f1a814007ce24bd4d51362991d5cb90ba0c177a9c08825f2cc304d871f \ - --hash=sha256:be243c7e2bfcf6cc4cb350c0d5cdf15ca6383bbcb2a8ef51d3c9411a9d4386f0 \ - --hash=sha256:bfbe6ee19615b07a98b1d2287d6a6073f734735b49ee45b11324d85efc4d5cbd \ - --hash=sha256:c46837ea467ed1efea562bbeb543994c2d1f6e800785bd5a2c98bc096f5cb220 \ - --hash=sha256:dfb4f4dd568de1b6af9f4cda334adf7d72cf5bc052516e1b2608b683375dd95c \ - --hash=sha256:ed7b00096790213e09eb11c97cc6e2b757f15f3d2f85833cd2d3ec3fe37c1722 +cryptography==39.0.1 \ + --hash=sha256:0f8da300b5c8af9f98111ffd512910bc792b4c77392a9523624680f7956a99d4 \ + --hash=sha256:35f7c7d015d474f4011e859e93e789c87d21f6f4880ebdc29896a60403328f1f \ + --hash=sha256:5aa67414fcdfa22cf052e640cb5ddc461924a045cacf325cd164e65312d99502 \ + --hash=sha256:5d2d8b87a490bfcd407ed9d49093793d0f75198a35e6eb1a923ce1ee86c62b41 \ + --hash=sha256:6687ef6d0a6497e2b58e7c5b852b53f62142cfa7cd1555795758934da363a965 \ + --hash=sha256:6f8ba7f0328b79f08bdacc3e4e66fb4d7aab0c3584e0bd41328dce5262e26b2e \ + --hash=sha256:706843b48f9a3f9b9911979761c91541e3d90db1ca905fd63fee540a217698bc \ + --hash=sha256:807ce09d4434881ca3a7594733669bd834f5b2c6d5c7e36f8c00f691887042ad \ + --hash=sha256:83e17b26de248c33f3acffb922748151d71827d6021d98c70e6c1a25ddd78505 \ + --hash=sha256:96f1157a7c08b5b189b16b47bc9db2332269d6680a196341bf30046330d15388 \ + --hash=sha256:aec5a6c9864be7df2240c382740fcf3b96928c46604eaa7f3091f58b878c0bb6 \ + --hash=sha256:b0afd054cd42f3d213bf82c629efb1ee5f22eba35bf0eec88ea9ea7304f511a2 \ + --hash=sha256:ced4e447ae29ca194449a3f1ce132ded8fcab06971ef5f618605aacaa612beac \ + --hash=sha256:d1f6198ee6d9148405e49887803907fe8962a23e6c6f83ea7d98f1c0de375695 \ + --hash=sha256:e124352fd3db36a9d4a21c1aa27fd5d051e621845cb87fb851c08f4f75ce8be6 \ + --hash=sha256:e422abdec8b5fa8462aa016786680720d78bdce7a30c652b7fadf83a4ba35336 \ + --hash=sha256:ef8b72fa70b348724ff1218267e7f7375b8de4e8194d1636ee60510aae104cd0 \ + --hash=sha256:f0c64d1bd842ca2633e74a1a28033d139368ad959872533b1bab8c80e8240a0c \ + --hash=sha256:f24077a3b5298a5a06a8e0536e3ea9ec60e4c7ac486755e5fb6e6ea9b3500106 \ + --hash=sha256:fdd188c8a6ef8769f148f88f859884507b954cc64db6b52f66ef199bb9ad660a \ + --hash=sha256:fe913f20024eb2cb2f323e42a64bdf2911bb9738a15dba7d3cce48151034e3a8 # via # gcp-releasetool # secretstorage From 31ff791cc4f4d83c1fb62be06e96147f0e4a7bb1 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 16 Feb 2023 11:57:18 +0000 Subject: [PATCH 07/10] chore(deps): update dependency flask to v2.2.3 (#622) --- samples/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index d2a43254c..8ae16b22c 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,2 +1,2 @@ google-cloud-dialogflow==2.19.1 -Flask==2.2.2 +Flask==2.2.3 From 1a932ee406982f3d8dc016f5397580507b716516 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 06:05:29 -0500 Subject: [PATCH 08/10] chore(python): upgrade gcp-releasetool in .kokoro [autoapprove] (#624) Source-Link: https://github.com/googleapis/synthtool/commit/5f2a6089f73abf06238fe4310f6a14d6f6d1eed3 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:8555f0e37e6261408f792bfd6635102d2da5ad73f8f09bcb24f25e6afb5fac97 Co-authored-by: Owl Bot --- .github/.OwlBot.lock.yaml | 2 +- .kokoro/requirements.in | 2 +- .kokoro/requirements.txt | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 894fb6bc9..5fc5daa31 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,4 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:f62c53736eccb0c4934a3ea9316e0d57696bb49c1a7c86c726e9bb8a2f87dadf + digest: sha256:8555f0e37e6261408f792bfd6635102d2da5ad73f8f09bcb24f25e6afb5fac97 diff --git a/.kokoro/requirements.in b/.kokoro/requirements.in index cbd7e77f4..882178ce6 100644 --- a/.kokoro/requirements.in +++ b/.kokoro/requirements.in @@ -1,5 +1,5 @@ gcp-docuploader -gcp-releasetool +gcp-releasetool>=1.10.5 # required for compatibility with cryptography>=39.x importlib-metadata typing-extensions twine diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt index 096e4800a..fa99c1290 100644 --- a/.kokoro/requirements.txt +++ b/.kokoro/requirements.txt @@ -154,9 +154,9 @@ gcp-docuploader==0.6.4 \ --hash=sha256:01486419e24633af78fd0167db74a2763974765ee8078ca6eb6964d0ebd388af \ --hash=sha256:70861190c123d907b3b067da896265ead2eeb9263969d6955c9e0bb091b5ccbf # via -r requirements.in -gcp-releasetool==1.10.0 \ - --hash=sha256:72a38ca91b59c24f7e699e9227c90cbe4dd71b789383cb0164b088abae294c83 \ - --hash=sha256:8c7c99320208383d4bb2b808c6880eb7a81424afe7cdba3c8d84b25f4f0e097d +gcp-releasetool==1.10.5 \ + --hash=sha256:174b7b102d704b254f2a26a3eda2c684fd3543320ec239baf771542a2e58e109 \ + --hash=sha256:e29d29927fe2ca493105a82958c6873bb2b90d503acac56be2c229e74de0eec9 # via -r requirements.in google-api-core==2.10.2 \ --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ From 03199c43fd509bd7bd2693ce6648e9defbea3cf2 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 07:06:32 -0500 Subject: [PATCH 09/10] feat: added support for AssistQueryParameters and SynthesizeSpeechConfig (#621) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: Update gapic-generator-python to v1.8.5 PiperOrigin-RevId: 511892190 Source-Link: https://github.com/googleapis/googleapis/commit/a45d9c09c1287ffdf938f4e8083e791046c0b23b Source-Link: https://github.com/googleapis/googleapis-gen/commit/1907294b1d8365ea24f8c5f2e059a64124c4ed3b Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiMTkwNzI5NGIxZDgzNjVlYTI0ZjhjNWYyZTA1OWE2NDEyNGM0ZWQzYiJ9 feat: added support for AssistQueryParameters and SynthesizeSpeechConfig docs: add more meaningful comments PiperOrigin-RevId: 510042252 Source-Link: https://github.com/googleapis/googleapis/commit/7b30db729561f4f426eedab20f2a54e54e87b4b5 Source-Link: https://github.com/googleapis/googleapis-gen/commit/17beb9941750b31faa423a29d7a018346a6b88b5 Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiMTdiZWI5OTQxNzUwYjMxZmFhNDIzYTI5ZDdhMDE4MzQ2YTZiODhiNSJ9 feat: enable "rest" transport in Python for services supporting numeric enums PiperOrigin-RevId: 508143576 Source-Link: https://github.com/googleapis/googleapis/commit/7a702a989db3b413f39ff8994ca53fb38b6928c2 Source-Link: https://github.com/googleapis/googleapis-gen/commit/6ad1279c0e7aa787ac6b66c9fd4a210692edffcd Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiNmFkMTI3OWMwZTdhYTc4N2FjNmI2NmM5ZmQ0YTIxMDY5MmVkZmZjZCJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot --- .../cloud/dialogflow_v2/gapic_metadata.json | 624 ++- .../dialogflow_v2/services/agents/client.py | 2 + .../services/agents/transports/__init__.py | 4 + .../services/agents/transports/rest.py | 1917 +++++++++ .../services/answer_records/client.py | 2 + .../answer_records/transports/__init__.py | 4 + .../answer_records/transports/rest.py | 953 +++++ .../dialogflow_v2/services/contexts/client.py | 2 + .../services/contexts/transports/__init__.py | 4 + .../services/contexts/transports/rest.py | 1489 +++++++ .../services/conversation_datasets/client.py | 2 + .../transports/__init__.py | 4 + .../conversation_datasets/transports/rest.py | 1429 +++++++ .../services/conversation_models/client.py | 2 + .../transports/__init__.py | 4 + .../conversation_models/transports/rest.py | 2013 +++++++++ .../services/conversation_profiles/client.py | 2 + .../transports/__init__.py | 4 + .../conversation_profiles/transports/rest.py | 1722 ++++++++ .../services/conversations/client.py | 2 + .../conversations/transports/__init__.py | 4 + .../services/conversations/transports/rest.py | 1504 +++++++ .../services/documents/client.py | 2 + .../services/documents/transports/__init__.py | 4 + .../services/documents/transports/rest.py | 1844 +++++++++ .../services/entity_types/client.py | 2 + .../entity_types/transports/__init__.py | 4 + .../services/entity_types/transports/rest.py | 2138 ++++++++++ .../services/environments/client.py | 2 + .../environments/transports/__init__.py | 4 + .../services/environments/transports/rest.py | 1496 +++++++ .../services/fulfillments/client.py | 2 + .../fulfillments/transports/__init__.py | 4 + .../services/fulfillments/transports/rest.py | 939 +++++ .../dialogflow_v2/services/intents/client.py | 2 + .../services/intents/transports/__init__.py | 4 + .../services/intents/transports/rest.py | 1665 ++++++++ .../services/knowledge_bases/client.py | 2 + .../knowledge_bases/transports/__init__.py | 4 + .../knowledge_bases/transports/rest.py | 1372 ++++++ .../services/participants/client.py | 2 + .../participants/transports/__init__.py | 4 + .../services/participants/transports/rest.py | 1817 ++++++++ .../services/session_entity_types/client.py | 2 + .../transports/__init__.py | 4 + .../session_entity_types/transports/rest.py | 1408 +++++++ .../dialogflow_v2/services/sessions/client.py | 2 + .../services/sessions/transports/__init__.py | 4 + .../services/sessions/transports/rest.py | 816 ++++ .../dialogflow_v2/services/versions/client.py | 2 + .../services/versions/transports/__init__.py | 4 + .../services/versions/transports/rest.py | 1333 ++++++ google/cloud/dialogflow_v2/types/agent.py | 2 + .../dialogflow_v2/types/answer_record.py | 2 + .../cloud/dialogflow_v2/types/audio_config.py | 2 + google/cloud/dialogflow_v2/types/context.py | 2 + .../cloud/dialogflow_v2/types/conversation.py | 9 + .../types/conversation_dataset.py | 2 + .../dialogflow_v2/types/conversation_event.py | 2 + .../dialogflow_v2/types/conversation_model.py | 2 + .../types/conversation_profile.py | 14 + google/cloud/dialogflow_v2/types/document.py | 2 + .../cloud/dialogflow_v2/types/entity_type.py | 2 + .../cloud/dialogflow_v2/types/environment.py | 2 + .../cloud/dialogflow_v2/types/fulfillment.py | 2 + google/cloud/dialogflow_v2/types/gcs.py | 2 + .../types/human_agent_assistant_event.py | 2 + google/cloud/dialogflow_v2/types/intent.py | 2 + .../dialogflow_v2/types/knowledge_base.py | 2 + .../cloud/dialogflow_v2/types/participant.py | 2 + google/cloud/dialogflow_v2/types/session.py | 2 + .../types/session_entity_type.py | 2 + .../dialogflow_v2/types/validation_result.py | 2 + google/cloud/dialogflow_v2/types/version.py | 2 + google/cloud/dialogflow_v2/types/webhook.py | 2 + .../dialogflow_v2beta1/gapic_metadata.json | 539 ++- .../services/agents/client.py | 2 + .../services/agents/transports/__init__.py | 4 + .../services/agents/transports/rest.py | 1918 +++++++++ .../services/answer_records/client.py | 2 + .../answer_records/transports/__init__.py | 4 + .../answer_records/transports/rest.py | 1093 +++++ .../services/contexts/client.py | 2 + .../services/contexts/transports/__init__.py | 4 + .../services/contexts/transports/rest.py | 1490 +++++++ .../services/conversation_profiles/client.py | 2 + .../transports/__init__.py | 4 + .../conversation_profiles/transports/rest.py | 1722 ++++++++ .../services/conversations/client.py | 2 + .../conversations/transports/__init__.py | 4 + .../services/conversations/transports/rest.py | 1652 ++++++++ .../services/documents/client.py | 2 + .../services/documents/transports/__init__.py | 4 + .../services/documents/transports/rest.py | 1702 ++++++++ .../services/entity_types/client.py | 2 + .../entity_types/transports/__init__.py | 4 + .../services/entity_types/transports/rest.py | 2138 ++++++++++ .../services/environments/client.py | 2 + .../environments/transports/__init__.py | 4 + .../services/environments/transports/rest.py | 1496 +++++++ .../services/fulfillments/client.py | 2 + .../fulfillments/transports/__init__.py | 4 + .../services/fulfillments/transports/rest.py | 939 +++++ .../services/intents/client.py | 2 + .../services/intents/transports/__init__.py | 4 + .../services/intents/transports/rest.py | 1668 ++++++++ .../services/knowledge_bases/client.py | 2 + .../knowledge_bases/transports/__init__.py | 4 + .../knowledge_bases/transports/rest.py | 1372 ++++++ .../services/participants/client.py | 2 + .../participants/transports/__init__.py | 4 + .../services/participants/transports/rest.py | 2070 +++++++++ .../services/session_entity_types/client.py | 2 + .../transports/__init__.py | 4 + .../session_entity_types/transports/rest.py | 1408 +++++++ .../services/sessions/client.py | 2 + .../services/sessions/transports/__init__.py | 4 + .../services/sessions/transports/rest.py | 816 ++++ .../services/versions/client.py | 2 + .../services/versions/transports/__init__.py | 4 + .../services/versions/transports/rest.py | 1334 ++++++ .../cloud/dialogflow_v2beta1/types/agent.py | 2 + .../dialogflow_v2beta1/types/answer_record.py | 2 + .../dialogflow_v2beta1/types/audio_config.py | 2 + .../cloud/dialogflow_v2beta1/types/context.py | 2 + .../dialogflow_v2beta1/types/conversation.py | 2 + .../types/conversation_event.py | 2 + .../types/conversation_profile.py | 2 + .../dialogflow_v2beta1/types/document.py | 2 + .../dialogflow_v2beta1/types/entity_type.py | 2 + .../dialogflow_v2beta1/types/environment.py | 2 + .../dialogflow_v2beta1/types/fulfillment.py | 2 + google/cloud/dialogflow_v2beta1/types/gcs.py | 2 + .../types/human_agent_assistant_event.py | 2 + .../cloud/dialogflow_v2beta1/types/intent.py | 2 + .../types/knowledge_base.py | 2 + .../dialogflow_v2beta1/types/participant.py | 2 + .../cloud/dialogflow_v2beta1/types/session.py | 2 + .../types/session_entity_type.py | 2 + .../types/validation_result.py | 2 + .../cloud/dialogflow_v2beta1/types/version.py | 2 + .../cloud/dialogflow_v2beta1/types/webhook.py | 2 + scripts/fixup_dialogflow_v2_keywords.py | 2 +- tests/unit/gapic/dialogflow_v2/test_agents.py | 2951 ++++++++++++- .../dialogflow_v2/test_answer_records.py | 1064 ++++- .../unit/gapic/dialogflow_v2/test_contexts.py | 2286 +++++++++- .../test_conversation_datasets.py | 2053 ++++++++- .../dialogflow_v2/test_conversation_models.py | 3235 ++++++++++++++- .../test_conversation_profiles.py | 3018 +++++++++++++- .../gapic/dialogflow_v2/test_conversations.py | 2414 ++++++++++- .../gapic/dialogflow_v2/test_documents.py | 2828 ++++++++++++- .../gapic/dialogflow_v2/test_entity_types.py | 3387 ++++++++++++++- .../gapic/dialogflow_v2/test_environments.py | 2173 +++++++++- .../gapic/dialogflow_v2/test_fulfillments.py | 950 ++++- .../unit/gapic/dialogflow_v2/test_intents.py | 3516 +++++++++++++++- .../dialogflow_v2/test_knowledge_bases.py | 2126 +++++++++- .../gapic/dialogflow_v2/test_participants.py | 2993 ++++++++++++- .../test_session_entity_types.py | 2234 +++++++++- .../unit/gapic/dialogflow_v2/test_sessions.py | 678 ++- .../unit/gapic/dialogflow_v2/test_versions.py | 2033 ++++++++- .../gapic/dialogflow_v2beta1/test_agents.py | 2943 ++++++++++++- .../dialogflow_v2beta1/test_answer_records.py | 1084 ++++- .../gapic/dialogflow_v2beta1/test_contexts.py | 2286 +++++++++- .../test_conversation_profiles.py | 2982 ++++++++++++- .../dialogflow_v2beta1/test_conversations.py | 2771 ++++++++++++- .../dialogflow_v2beta1/test_documents.py | 2712 +++++++++++- .../dialogflow_v2beta1/test_entity_types.py | 3389 ++++++++++++++- .../dialogflow_v2beta1/test_environments.py | 2174 +++++++++- .../dialogflow_v2beta1/test_fulfillments.py | 950 ++++- .../gapic/dialogflow_v2beta1/test_intents.py | 3687 ++++++++++++++++- .../test_knowledge_bases.py | 2130 +++++++++- .../dialogflow_v2beta1/test_participants.py | 3361 ++++++++++++++- .../test_session_entity_types.py | 2234 +++++++++- .../gapic/dialogflow_v2beta1/test_sessions.py | 678 ++- .../gapic/dialogflow_v2beta1/test_versions.py | 2038 ++++++++- 175 files changed, 121980 insertions(+), 3515 deletions(-) create mode 100644 google/cloud/dialogflow_v2/services/agents/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/answer_records/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/contexts/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/conversation_datasets/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/conversation_models/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/conversation_profiles/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/conversations/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/documents/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/entity_types/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/environments/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/fulfillments/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/intents/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/knowledge_bases/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/participants/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/session_entity_types/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/sessions/transports/rest.py create mode 100644 google/cloud/dialogflow_v2/services/versions/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/agents/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/answer_records/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/contexts/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/conversation_profiles/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/conversations/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/documents/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/entity_types/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/environments/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/fulfillments/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/intents/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/knowledge_bases/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/participants/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/session_entity_types/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/sessions/transports/rest.py create mode 100644 google/cloud/dialogflow_v2beta1/services/versions/transports/rest.py diff --git a/google/cloud/dialogflow_v2/gapic_metadata.json b/google/cloud/dialogflow_v2/gapic_metadata.json index 6e20fa1a0..59e9b0fa5 100644 --- a/google/cloud/dialogflow_v2/gapic_metadata.json +++ b/google/cloud/dialogflow_v2/gapic_metadata.json @@ -106,6 +106,56 @@ ] } } + }, + "rest": { + "libraryClient": "AgentsClient", + "rpcs": { + "DeleteAgent": { + "methods": [ + "delete_agent" + ] + }, + "ExportAgent": { + "methods": [ + "export_agent" + ] + }, + "GetAgent": { + "methods": [ + "get_agent" + ] + }, + "GetValidationResult": { + "methods": [ + "get_validation_result" + ] + }, + "ImportAgent": { + "methods": [ + "import_agent" + ] + }, + "RestoreAgent": { + "methods": [ + "restore_agent" + ] + }, + "SearchAgents": { + "methods": [ + "search_agents" + ] + }, + "SetAgent": { + "methods": [ + "set_agent" + ] + }, + "TrainAgent": { + "methods": [ + "train_agent" + ] + } + } } } }, @@ -140,6 +190,21 @@ ] } } + }, + "rest": { + "libraryClient": "AnswerRecordsClient", + "rpcs": { + "ListAnswerRecords": { + "methods": [ + "list_answer_records" + ] + }, + "UpdateAnswerRecord": { + "methods": [ + "update_answer_record" + ] + } + } } } }, @@ -214,6 +279,41 @@ ] } } + }, + "rest": { + "libraryClient": "ContextsClient", + "rpcs": { + "CreateContext": { + "methods": [ + "create_context" + ] + }, + "DeleteAllContexts": { + "methods": [ + "delete_all_contexts" + ] + }, + "DeleteContext": { + "methods": [ + "delete_context" + ] + }, + "GetContext": { + "methods": [ + "get_context" + ] + }, + "ListContexts": { + "methods": [ + "list_contexts" + ] + }, + "UpdateContext": { + "methods": [ + "update_context" + ] + } + } } } }, @@ -278,6 +378,36 @@ ] } } + }, + "rest": { + "libraryClient": "ConversationDatasetsClient", + "rpcs": { + "CreateConversationDataset": { + "methods": [ + "create_conversation_dataset" + ] + }, + "DeleteConversationDataset": { + "methods": [ + "delete_conversation_dataset" + ] + }, + "GetConversationDataset": { + "methods": [ + "get_conversation_dataset" + ] + }, + "ImportConversationData": { + "methods": [ + "import_conversation_data" + ] + }, + "ListConversationDatasets": { + "methods": [ + "list_conversation_datasets" + ] + } + } } } }, @@ -382,6 +512,56 @@ ] } } + }, + "rest": { + "libraryClient": "ConversationModelsClient", + "rpcs": { + "CreateConversationModel": { + "methods": [ + "create_conversation_model" + ] + }, + "CreateConversationModelEvaluation": { + "methods": [ + "create_conversation_model_evaluation" + ] + }, + "DeleteConversationModel": { + "methods": [ + "delete_conversation_model" + ] + }, + "DeployConversationModel": { + "methods": [ + "deploy_conversation_model" + ] + }, + "GetConversationModel": { + "methods": [ + "get_conversation_model" + ] + }, + "GetConversationModelEvaluation": { + "methods": [ + "get_conversation_model_evaluation" + ] + }, + "ListConversationModelEvaluations": { + "methods": [ + "list_conversation_model_evaluations" + ] + }, + "ListConversationModels": { + "methods": [ + "list_conversation_models" + ] + }, + "UndeployConversationModel": { + "methods": [ + "undeploy_conversation_model" + ] + } + } } } }, @@ -466,6 +646,46 @@ ] } } + }, + "rest": { + "libraryClient": "ConversationProfilesClient", + "rpcs": { + "ClearSuggestionFeatureConfig": { + "methods": [ + "clear_suggestion_feature_config" + ] + }, + "CreateConversationProfile": { + "methods": [ + "create_conversation_profile" + ] + }, + "DeleteConversationProfile": { + "methods": [ + "delete_conversation_profile" + ] + }, + "GetConversationProfile": { + "methods": [ + "get_conversation_profile" + ] + }, + "ListConversationProfiles": { + "methods": [ + "list_conversation_profiles" + ] + }, + "SetSuggestionFeatureConfig": { + "methods": [ + "set_suggestion_feature_config" + ] + }, + "UpdateConversationProfile": { + "methods": [ + "update_conversation_profile" + ] + } + } } } }, @@ -540,6 +760,41 @@ ] } } + }, + "rest": { + "libraryClient": "ConversationsClient", + "rpcs": { + "CompleteConversation": { + "methods": [ + "complete_conversation" + ] + }, + "CreateConversation": { + "methods": [ + "create_conversation" + ] + }, + "GetConversation": { + "methods": [ + "get_conversation" + ] + }, + "ListConversations": { + "methods": [ + "list_conversations" + ] + }, + "ListMessages": { + "methods": [ + "list_messages" + ] + }, + "SuggestConversationSummary": { + "methods": [ + "suggest_conversation_summary" + ] + } + } } } }, @@ -625,22 +880,122 @@ }, "ReloadDocument": { "methods": [ - "reload_document" + "reload_document" + ] + }, + "UpdateDocument": { + "methods": [ + "update_document" + ] + } + } + }, + "rest": { + "libraryClient": "DocumentsClient", + "rpcs": { + "CreateDocument": { + "methods": [ + "create_document" + ] + }, + "DeleteDocument": { + "methods": [ + "delete_document" + ] + }, + "ExportDocument": { + "methods": [ + "export_document" + ] + }, + "GetDocument": { + "methods": [ + "get_document" + ] + }, + "ImportDocuments": { + "methods": [ + "import_documents" + ] + }, + "ListDocuments": { + "methods": [ + "list_documents" + ] + }, + "ReloadDocument": { + "methods": [ + "reload_document" + ] + }, + "UpdateDocument": { + "methods": [ + "update_document" + ] + } + } + } + } + }, + "EntityTypes": { + "clients": { + "grpc": { + "libraryClient": "EntityTypesClient", + "rpcs": { + "BatchCreateEntities": { + "methods": [ + "batch_create_entities" + ] + }, + "BatchDeleteEntities": { + "methods": [ + "batch_delete_entities" + ] + }, + "BatchDeleteEntityTypes": { + "methods": [ + "batch_delete_entity_types" + ] + }, + "BatchUpdateEntities": { + "methods": [ + "batch_update_entities" + ] + }, + "BatchUpdateEntityTypes": { + "methods": [ + "batch_update_entity_types" + ] + }, + "CreateEntityType": { + "methods": [ + "create_entity_type" + ] + }, + "DeleteEntityType": { + "methods": [ + "delete_entity_type" + ] + }, + "GetEntityType": { + "methods": [ + "get_entity_type" + ] + }, + "ListEntityTypes": { + "methods": [ + "list_entity_types" ] }, - "UpdateDocument": { + "UpdateEntityType": { "methods": [ - "update_document" + "update_entity_type" ] } } - } - } - }, - "EntityTypes": { - "clients": { - "grpc": { - "libraryClient": "EntityTypesClient", + }, + "grpc-async": { + "libraryClient": "EntityTypesAsyncClient", "rpcs": { "BatchCreateEntities": { "methods": [ @@ -694,8 +1049,8 @@ } } }, - "grpc-async": { - "libraryClient": "EntityTypesAsyncClient", + "rest": { + "libraryClient": "EntityTypesClient", "rpcs": { "BatchCreateEntities": { "methods": [ @@ -822,6 +1177,41 @@ ] } } + }, + "rest": { + "libraryClient": "EnvironmentsClient", + "rpcs": { + "CreateEnvironment": { + "methods": [ + "create_environment" + ] + }, + "DeleteEnvironment": { + "methods": [ + "delete_environment" + ] + }, + "GetEnvironment": { + "methods": [ + "get_environment" + ] + }, + "GetEnvironmentHistory": { + "methods": [ + "get_environment_history" + ] + }, + "ListEnvironments": { + "methods": [ + "list_environments" + ] + }, + "UpdateEnvironment": { + "methods": [ + "update_environment" + ] + } + } } } }, @@ -856,6 +1246,21 @@ ] } } + }, + "rest": { + "libraryClient": "FulfillmentsClient", + "rpcs": { + "GetFulfillment": { + "methods": [ + "get_fulfillment" + ] + }, + "UpdateFulfillment": { + "methods": [ + "update_fulfillment" + ] + } + } } } }, @@ -940,6 +1345,46 @@ ] } } + }, + "rest": { + "libraryClient": "IntentsClient", + "rpcs": { + "BatchDeleteIntents": { + "methods": [ + "batch_delete_intents" + ] + }, + "BatchUpdateIntents": { + "methods": [ + "batch_update_intents" + ] + }, + "CreateIntent": { + "methods": [ + "create_intent" + ] + }, + "DeleteIntent": { + "methods": [ + "delete_intent" + ] + }, + "GetIntent": { + "methods": [ + "get_intent" + ] + }, + "ListIntents": { + "methods": [ + "list_intents" + ] + }, + "UpdateIntent": { + "methods": [ + "update_intent" + ] + } + } } } }, @@ -1004,6 +1449,36 @@ ] } } + }, + "rest": { + "libraryClient": "KnowledgeBasesClient", + "rpcs": { + "CreateKnowledgeBase": { + "methods": [ + "create_knowledge_base" + ] + }, + "DeleteKnowledgeBase": { + "methods": [ + "delete_knowledge_base" + ] + }, + "GetKnowledgeBase": { + "methods": [ + "get_knowledge_base" + ] + }, + "ListKnowledgeBases": { + "methods": [ + "list_knowledge_bases" + ] + }, + "UpdateKnowledgeBase": { + "methods": [ + "update_knowledge_base" + ] + } + } } } }, @@ -1108,6 +1583,56 @@ ] } } + }, + "rest": { + "libraryClient": "ParticipantsClient", + "rpcs": { + "AnalyzeContent": { + "methods": [ + "analyze_content" + ] + }, + "CreateParticipant": { + "methods": [ + "create_participant" + ] + }, + "GetParticipant": { + "methods": [ + "get_participant" + ] + }, + "ListParticipants": { + "methods": [ + "list_participants" + ] + }, + "StreamingAnalyzeContent": { + "methods": [ + "streaming_analyze_content" + ] + }, + "SuggestArticles": { + "methods": [ + "suggest_articles" + ] + }, + "SuggestFaqAnswers": { + "methods": [ + "suggest_faq_answers" + ] + }, + "SuggestSmartReplies": { + "methods": [ + "suggest_smart_replies" + ] + }, + "UpdateParticipant": { + "methods": [ + "update_participant" + ] + } + } } } }, @@ -1172,6 +1697,36 @@ ] } } + }, + "rest": { + "libraryClient": "SessionEntityTypesClient", + "rpcs": { + "CreateSessionEntityType": { + "methods": [ + "create_session_entity_type" + ] + }, + "DeleteSessionEntityType": { + "methods": [ + "delete_session_entity_type" + ] + }, + "GetSessionEntityType": { + "methods": [ + "get_session_entity_type" + ] + }, + "ListSessionEntityTypes": { + "methods": [ + "list_session_entity_types" + ] + }, + "UpdateSessionEntityType": { + "methods": [ + "update_session_entity_type" + ] + } + } } } }, @@ -1206,6 +1761,21 @@ ] } } + }, + "rest": { + "libraryClient": "SessionsClient", + "rpcs": { + "DetectIntent": { + "methods": [ + "detect_intent" + ] + }, + "StreamingDetectIntent": { + "methods": [ + "streaming_detect_intent" + ] + } + } } } }, @@ -1270,6 +1840,36 @@ ] } } + }, + "rest": { + "libraryClient": "VersionsClient", + "rpcs": { + "CreateVersion": { + "methods": [ + "create_version" + ] + }, + "DeleteVersion": { + "methods": [ + "delete_version" + ] + }, + "GetVersion": { + "methods": [ + "get_version" + ] + }, + "ListVersions": { + "methods": [ + "list_versions" + ] + }, + "UpdateVersion": { + "methods": [ + "update_version" + ] + } + } } } } diff --git a/google/cloud/dialogflow_v2/services/agents/client.py b/google/cloud/dialogflow_v2/services/agents/client.py index 6b774db6e..aa3e68dec 100644 --- a/google/cloud/dialogflow_v2/services/agents/client.py +++ b/google/cloud/dialogflow_v2/services/agents/client.py @@ -61,6 +61,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, AgentsTransport from .transports.grpc import AgentsGrpcTransport from .transports.grpc_asyncio import AgentsGrpcAsyncIOTransport +from .transports.rest import AgentsRestTransport class AgentsClientMeta(type): @@ -74,6 +75,7 @@ class AgentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[AgentsTransport]] _transport_registry["grpc"] = AgentsGrpcTransport _transport_registry["grpc_asyncio"] = AgentsGrpcAsyncIOTransport + _transport_registry["rest"] = AgentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/agents/transports/__init__.py b/google/cloud/dialogflow_v2/services/agents/transports/__init__.py index fa8faf8d6..38b6ef776 100644 --- a/google/cloud/dialogflow_v2/services/agents/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/agents/transports/__init__.py @@ -19,14 +19,18 @@ from .base import AgentsTransport from .grpc import AgentsGrpcTransport from .grpc_asyncio import AgentsGrpcAsyncIOTransport +from .rest import AgentsRestInterceptor, AgentsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[AgentsTransport]] _transport_registry["grpc"] = AgentsGrpcTransport _transport_registry["grpc_asyncio"] = AgentsGrpcAsyncIOTransport +_transport_registry["rest"] = AgentsRestTransport __all__ = ( "AgentsTransport", "AgentsGrpcTransport", "AgentsGrpcAsyncIOTransport", + "AgentsRestTransport", + "AgentsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/agents/transports/rest.py b/google/cloud/dialogflow_v2/services/agents/transports/rest.py new file mode 100644 index 000000000..eda64e40e --- /dev/null +++ b/google/cloud/dialogflow_v2/services/agents/transports/rest.py @@ -0,0 +1,1917 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import agent +from google.cloud.dialogflow_v2.types import agent as gcd_agent +from google.cloud.dialogflow_v2.types import validation_result + +from .base import AgentsTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class AgentsRestInterceptor: + """Interceptor for Agents. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the AgentsRestTransport. + + .. code-block:: python + class MyCustomAgentsInterceptor(AgentsRestInterceptor): + def pre_delete_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_export_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_export_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_validation_result(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_validation_result(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_import_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_import_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_restore_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_restore_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_search_agents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_search_agents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_set_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_set_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_train_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_train_agent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = AgentsRestTransport(interceptor=MyCustomAgentsInterceptor()) + client = AgentsClient(transport=transport) + + + """ + + def pre_delete_agent( + self, request: agent.DeleteAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.DeleteAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def pre_export_agent( + self, request: agent.ExportAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.ExportAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for export_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_export_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for export_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_agent( + self, request: agent.GetAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.GetAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_agent(self, response: agent.Agent) -> agent.Agent: + """Post-rpc interceptor for get_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_validation_result( + self, + request: agent.GetValidationResultRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[agent.GetValidationResultRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_validation_result + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_validation_result( + self, response: validation_result.ValidationResult + ) -> validation_result.ValidationResult: + """Post-rpc interceptor for get_validation_result + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_import_agent( + self, request: agent.ImportAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.ImportAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for import_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_import_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for import_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_restore_agent( + self, request: agent.RestoreAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.RestoreAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for restore_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_restore_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for restore_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_search_agents( + self, request: agent.SearchAgentsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.SearchAgentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for search_agents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_search_agents( + self, response: agent.SearchAgentsResponse + ) -> agent.SearchAgentsResponse: + """Post-rpc interceptor for search_agents + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_set_agent( + self, request: gcd_agent.SetAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcd_agent.SetAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for set_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_set_agent(self, response: gcd_agent.Agent) -> gcd_agent.Agent: + """Post-rpc interceptor for set_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_train_agent( + self, request: agent.TrainAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.TrainAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for train_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_train_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for train_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class AgentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: AgentsRestInterceptor + + +class AgentsRestTransport(AgentsTransport): + """REST backend transport for Agents. + + Service for managing [Agents][google.cloud.dialogflow.v2.Agent]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[AgentsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or AgentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _DeleteAgent(AgentsRestStub): + def __hash__(self): + return hash("DeleteAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.DeleteAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete agent method over HTTP. + + Args: + request (~.agent.DeleteAgentRequest): + The request object. The request message for + [Agents.DeleteAgent][google.cloud.dialogflow.v2.Agents.DeleteAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{parent=projects/*}/agent", + }, + { + "method": "delete", + "uri": "/v2/{parent=projects/*/locations/*}/agent", + }, + ] + request, metadata = self._interceptor.pre_delete_agent(request, metadata) + pb_request = agent.DeleteAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _ExportAgent(AgentsRestStub): + def __hash__(self): + return hash("ExportAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.ExportAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the export agent method over HTTP. + + Args: + request (~.agent.ExportAgentRequest): + The request object. The request message for + [Agents.ExportAgent][google.cloud.dialogflow.v2.Agents.ExportAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*}/agent:export", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*}/agent:export", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_export_agent(request, metadata) + pb_request = agent.ExportAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_export_agent(resp) + return resp + + class _GetAgent(AgentsRestStub): + def __hash__(self): + return hash("GetAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.GetAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.Agent: + r"""Call the get agent method over HTTP. + + Args: + request (~.agent.GetAgentRequest): + The request object. The request message for + [Agents.GetAgent][google.cloud.dialogflow.v2.Agents.GetAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.agent.Agent: + A Dialogflow agent is a virtual agent that handles + conversations with your end-users. It is a natural + language understanding module that understands the + nuances of human language. Dialogflow translates + end-user text or audio during a conversation to + structured data that your apps and services can + understand. You design and build a Dialogflow agent to + handle the types of conversations required for your + system. + + For more information about agents, see the `Agent + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*}/agent", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*}/agent", + }, + ] + request, metadata = self._interceptor.pre_get_agent(request, metadata) + pb_request = agent.GetAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = agent.Agent() + pb_resp = agent.Agent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_agent(resp) + return resp + + class _GetValidationResult(AgentsRestStub): + def __hash__(self): + return hash("GetValidationResult") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.GetValidationResultRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> validation_result.ValidationResult: + r"""Call the get validation result method over HTTP. + + Args: + request (~.agent.GetValidationResultRequest): + The request object. The request message for + [Agents.GetValidationResult][google.cloud.dialogflow.v2.Agents.GetValidationResult]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.validation_result.ValidationResult: + Represents the output of agent + validation. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*}/agent/validationResult", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*}/agent/validationResult", + }, + ] + request, metadata = self._interceptor.pre_get_validation_result( + request, metadata + ) + pb_request = agent.GetValidationResultRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = validation_result.ValidationResult() + pb_resp = validation_result.ValidationResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_validation_result(resp) + return resp + + class _ImportAgent(AgentsRestStub): + def __hash__(self): + return hash("ImportAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.ImportAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the import agent method over HTTP. + + Args: + request (~.agent.ImportAgentRequest): + The request object. The request message for + [Agents.ImportAgent][google.cloud.dialogflow.v2.Agents.ImportAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*}/agent:import", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*}/agent:import", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_import_agent(request, metadata) + pb_request = agent.ImportAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_import_agent(resp) + return resp + + class _RestoreAgent(AgentsRestStub): + def __hash__(self): + return hash("RestoreAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.RestoreAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the restore agent method over HTTP. + + Args: + request (~.agent.RestoreAgentRequest): + The request object. The request message for + [Agents.RestoreAgent][google.cloud.dialogflow.v2.Agents.RestoreAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*}/agent:restore", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*}/agent:restore", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_restore_agent(request, metadata) + pb_request = agent.RestoreAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_restore_agent(resp) + return resp + + class _SearchAgents(AgentsRestStub): + def __hash__(self): + return hash("SearchAgents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.SearchAgentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.SearchAgentsResponse: + r"""Call the search agents method over HTTP. + + Args: + request (~.agent.SearchAgentsRequest): + The request object. The request message for + [Agents.SearchAgents][google.cloud.dialogflow.v2.Agents.SearchAgents]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.agent.SearchAgentsResponse: + The response message for + [Agents.SearchAgents][google.cloud.dialogflow.v2.Agents.SearchAgents]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*}/agent:search", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*}/agent:search", + }, + ] + request, metadata = self._interceptor.pre_search_agents(request, metadata) + pb_request = agent.SearchAgentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = agent.SearchAgentsResponse() + pb_resp = agent.SearchAgentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_search_agents(resp) + return resp + + class _SetAgent(AgentsRestStub): + def __hash__(self): + return hash("SetAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_agent.SetAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_agent.Agent: + r"""Call the set agent method over HTTP. + + Args: + request (~.gcd_agent.SetAgentRequest): + The request object. The request message for + [Agents.SetAgent][google.cloud.dialogflow.v2.Agents.SetAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_agent.Agent: + A Dialogflow agent is a virtual agent that handles + conversations with your end-users. It is a natural + language understanding module that understands the + nuances of human language. Dialogflow translates + end-user text or audio during a conversation to + structured data that your apps and services can + understand. You design and build a Dialogflow agent to + handle the types of conversations required for your + system. + + For more information about agents, see the `Agent + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{agent.parent=projects/*}/agent", + "body": "agent", + }, + { + "method": "post", + "uri": "/v2/{agent.parent=projects/*/locations/*}/agent", + "body": "agent", + }, + ] + request, metadata = self._interceptor.pre_set_agent(request, metadata) + pb_request = gcd_agent.SetAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_agent.Agent() + pb_resp = gcd_agent.Agent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_set_agent(resp) + return resp + + class _TrainAgent(AgentsRestStub): + def __hash__(self): + return hash("TrainAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.TrainAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the train agent method over HTTP. + + Args: + request (~.agent.TrainAgentRequest): + The request object. The request message for + [Agents.TrainAgent][google.cloud.dialogflow.v2.Agents.TrainAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*}/agent:train", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*}/agent:train", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_train_agent(request, metadata) + pb_request = agent.TrainAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_train_agent(resp) + return resp + + @property + def delete_agent(self) -> Callable[[agent.DeleteAgentRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def export_agent( + self, + ) -> Callable[[agent.ExportAgentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ExportAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_agent(self) -> Callable[[agent.GetAgentRequest], agent.Agent]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_validation_result( + self, + ) -> Callable[ + [agent.GetValidationResultRequest], validation_result.ValidationResult + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetValidationResult(self._session, self._host, self._interceptor) # type: ignore + + @property + def import_agent( + self, + ) -> Callable[[agent.ImportAgentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ImportAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def restore_agent( + self, + ) -> Callable[[agent.RestoreAgentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._RestoreAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def search_agents( + self, + ) -> Callable[[agent.SearchAgentsRequest], agent.SearchAgentsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SearchAgents(self._session, self._host, self._interceptor) # type: ignore + + @property + def set_agent(self) -> Callable[[gcd_agent.SetAgentRequest], gcd_agent.Agent]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SetAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def train_agent( + self, + ) -> Callable[[agent.TrainAgentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._TrainAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(AgentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(AgentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(AgentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(AgentsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(AgentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("AgentsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/answer_records/client.py b/google/cloud/dialogflow_v2/services/answer_records/client.py index 639cafa98..ad38e6ab3 100644 --- a/google/cloud/dialogflow_v2/services/answer_records/client.py +++ b/google/cloud/dialogflow_v2/services/answer_records/client.py @@ -57,6 +57,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, AnswerRecordsTransport from .transports.grpc import AnswerRecordsGrpcTransport from .transports.grpc_asyncio import AnswerRecordsGrpcAsyncIOTransport +from .transports.rest import AnswerRecordsRestTransport class AnswerRecordsClientMeta(type): @@ -70,6 +71,7 @@ class AnswerRecordsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[AnswerRecordsTransport]] _transport_registry["grpc"] = AnswerRecordsGrpcTransport _transport_registry["grpc_asyncio"] = AnswerRecordsGrpcAsyncIOTransport + _transport_registry["rest"] = AnswerRecordsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/answer_records/transports/__init__.py b/google/cloud/dialogflow_v2/services/answer_records/transports/__init__.py index 08caa497a..3b2af894e 100644 --- a/google/cloud/dialogflow_v2/services/answer_records/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/answer_records/transports/__init__.py @@ -19,14 +19,18 @@ from .base import AnswerRecordsTransport from .grpc import AnswerRecordsGrpcTransport from .grpc_asyncio import AnswerRecordsGrpcAsyncIOTransport +from .rest import AnswerRecordsRestInterceptor, AnswerRecordsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[AnswerRecordsTransport]] _transport_registry["grpc"] = AnswerRecordsGrpcTransport _transport_registry["grpc_asyncio"] = AnswerRecordsGrpcAsyncIOTransport +_transport_registry["rest"] = AnswerRecordsRestTransport __all__ = ( "AnswerRecordsTransport", "AnswerRecordsGrpcTransport", "AnswerRecordsGrpcAsyncIOTransport", + "AnswerRecordsRestTransport", + "AnswerRecordsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/answer_records/transports/rest.py b/google/cloud/dialogflow_v2/services/answer_records/transports/rest.py new file mode 100644 index 000000000..f679e4297 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/answer_records/transports/rest.py @@ -0,0 +1,953 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.dialogflow_v2.types import answer_record +from google.cloud.dialogflow_v2.types import answer_record as gcd_answer_record + +from .base import AnswerRecordsTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class AnswerRecordsRestInterceptor: + """Interceptor for AnswerRecords. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the AnswerRecordsRestTransport. + + .. code-block:: python + class MyCustomAnswerRecordsInterceptor(AnswerRecordsRestInterceptor): + def pre_list_answer_records(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_answer_records(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_answer_record(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_answer_record(self, response): + logging.log(f"Received response: {response}") + return response + + transport = AnswerRecordsRestTransport(interceptor=MyCustomAnswerRecordsInterceptor()) + client = AnswerRecordsClient(transport=transport) + + + """ + + def pre_list_answer_records( + self, + request: answer_record.ListAnswerRecordsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[answer_record.ListAnswerRecordsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_answer_records + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_list_answer_records( + self, response: answer_record.ListAnswerRecordsResponse + ) -> answer_record.ListAnswerRecordsResponse: + """Post-rpc interceptor for list_answer_records + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_update_answer_record( + self, + request: gcd_answer_record.UpdateAnswerRecordRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_answer_record.UpdateAnswerRecordRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_answer_record + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_update_answer_record( + self, response: gcd_answer_record.AnswerRecord + ) -> gcd_answer_record.AnswerRecord: + """Post-rpc interceptor for update_answer_record + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class AnswerRecordsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: AnswerRecordsRestInterceptor + + +class AnswerRecordsRestTransport(AnswerRecordsTransport): + """REST backend transport for AnswerRecords. + + Service for managing + [AnswerRecords][google.cloud.dialogflow.v2.AnswerRecord]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[AnswerRecordsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or AnswerRecordsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _ListAnswerRecords(AnswerRecordsRestStub): + def __hash__(self): + return hash("ListAnswerRecords") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: answer_record.ListAnswerRecordsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> answer_record.ListAnswerRecordsResponse: + r"""Call the list answer records method over HTTP. + + Args: + request (~.answer_record.ListAnswerRecordsRequest): + The request object. Request message for + [AnswerRecords.ListAnswerRecords][google.cloud.dialogflow.v2.AnswerRecords.ListAnswerRecords]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.answer_record.ListAnswerRecordsResponse: + Response message for + [AnswerRecords.ListAnswerRecords][google.cloud.dialogflow.v2.AnswerRecords.ListAnswerRecords]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*}/answerRecords", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*}/answerRecords", + }, + ] + request, metadata = self._interceptor.pre_list_answer_records( + request, metadata + ) + pb_request = answer_record.ListAnswerRecordsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = answer_record.ListAnswerRecordsResponse() + pb_resp = answer_record.ListAnswerRecordsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_answer_records(resp) + return resp + + class _UpdateAnswerRecord(AnswerRecordsRestStub): + def __hash__(self): + return hash("UpdateAnswerRecord") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_answer_record.UpdateAnswerRecordRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_answer_record.AnswerRecord: + r"""Call the update answer record method over HTTP. + + Args: + request (~.gcd_answer_record.UpdateAnswerRecordRequest): + The request object. Request message for + [AnswerRecords.UpdateAnswerRecord][google.cloud.dialogflow.v2.AnswerRecords.UpdateAnswerRecord]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_answer_record.AnswerRecord: + Answer records are records to manage answer history and + feedbacks for Dialogflow. + + Currently, answer record includes: + + - human agent assistant article suggestion + - human agent assistant faq article + + It doesn't include: + + - ``DetectIntent`` intent matching + - ``DetectIntent`` knowledge + + Answer records are not related to the conversation + history in the Dialogflow Console. A Record is generated + even when the end-user disables conversation history in + the console. Records are created when there's a human + agent assistant suggestion generated. + + A typical workflow for customers provide feedback to an + answer is: + + 1. For human agent assistant, customers get suggestion + via ListSuggestions API. Together with the answers, + [AnswerRecord.name][google.cloud.dialogflow.v2.AnswerRecord.name] + are returned to the customers. + 2. The customer uses the + [AnswerRecord.name][google.cloud.dialogflow.v2.AnswerRecord.name] + to call the [UpdateAnswerRecord][] method to send + feedback about a specific answer that they believe is + wrong. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{answer_record.name=projects/*/answerRecords/*}", + "body": "answer_record", + }, + { + "method": "patch", + "uri": "/v2/{answer_record.name=projects/*/locations/*/answerRecords/*}", + "body": "answer_record", + }, + ] + request, metadata = self._interceptor.pre_update_answer_record( + request, metadata + ) + pb_request = gcd_answer_record.UpdateAnswerRecordRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_answer_record.AnswerRecord() + pb_resp = gcd_answer_record.AnswerRecord.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_answer_record(resp) + return resp + + @property + def list_answer_records( + self, + ) -> Callable[ + [answer_record.ListAnswerRecordsRequest], + answer_record.ListAnswerRecordsResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListAnswerRecords(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_answer_record( + self, + ) -> Callable[ + [gcd_answer_record.UpdateAnswerRecordRequest], gcd_answer_record.AnswerRecord + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateAnswerRecord(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(AnswerRecordsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(AnswerRecordsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(AnswerRecordsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(AnswerRecordsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(AnswerRecordsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("AnswerRecordsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/contexts/client.py b/google/cloud/dialogflow_v2/services/contexts/client.py index 69c106a92..59ce634ed 100644 --- a/google/cloud/dialogflow_v2/services/contexts/client.py +++ b/google/cloud/dialogflow_v2/services/contexts/client.py @@ -58,6 +58,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, ContextsTransport from .transports.grpc import ContextsGrpcTransport from .transports.grpc_asyncio import ContextsGrpcAsyncIOTransport +from .transports.rest import ContextsRestTransport class ContextsClientMeta(type): @@ -71,6 +72,7 @@ class ContextsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[ContextsTransport]] _transport_registry["grpc"] = ContextsGrpcTransport _transport_registry["grpc_asyncio"] = ContextsGrpcAsyncIOTransport + _transport_registry["rest"] = ContextsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/contexts/transports/__init__.py b/google/cloud/dialogflow_v2/services/contexts/transports/__init__.py index decaf2fd8..2bb76253d 100644 --- a/google/cloud/dialogflow_v2/services/contexts/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/contexts/transports/__init__.py @@ -19,14 +19,18 @@ from .base import ContextsTransport from .grpc import ContextsGrpcTransport from .grpc_asyncio import ContextsGrpcAsyncIOTransport +from .rest import ContextsRestInterceptor, ContextsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[ContextsTransport]] _transport_registry["grpc"] = ContextsGrpcTransport _transport_registry["grpc_asyncio"] = ContextsGrpcAsyncIOTransport +_transport_registry["rest"] = ContextsRestTransport __all__ = ( "ContextsTransport", "ContextsGrpcTransport", "ContextsGrpcAsyncIOTransport", + "ContextsRestTransport", + "ContextsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/contexts/transports/rest.py b/google/cloud/dialogflow_v2/services/contexts/transports/rest.py new file mode 100644 index 000000000..46a87e428 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/contexts/transports/rest.py @@ -0,0 +1,1489 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import context +from google.cloud.dialogflow_v2.types import context as gcd_context + +from .base import ContextsTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class ContextsRestInterceptor: + """Interceptor for Contexts. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the ContextsRestTransport. + + .. code-block:: python + class MyCustomContextsInterceptor(ContextsRestInterceptor): + def pre_create_context(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_context(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_all_contexts(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_delete_context(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_context(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_context(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_contexts(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_contexts(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_context(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_context(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ContextsRestTransport(interceptor=MyCustomContextsInterceptor()) + client = ContextsClient(transport=transport) + + + """ + + def pre_create_context( + self, + request: gcd_context.CreateContextRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_context.CreateContextRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_context + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_create_context(self, response: gcd_context.Context) -> gcd_context.Context: + """Post-rpc interceptor for create_context + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_delete_all_contexts( + self, + request: context.DeleteAllContextsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[context.DeleteAllContextsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_all_contexts + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def pre_delete_context( + self, request: context.DeleteContextRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[context.DeleteContextRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_context + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def pre_get_context( + self, request: context.GetContextRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[context.GetContextRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_context + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_get_context(self, response: context.Context) -> context.Context: + """Post-rpc interceptor for get_context + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_list_contexts( + self, request: context.ListContextsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[context.ListContextsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_contexts + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_list_contexts( + self, response: context.ListContextsResponse + ) -> context.ListContextsResponse: + """Post-rpc interceptor for list_contexts + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_update_context( + self, + request: gcd_context.UpdateContextRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_context.UpdateContextRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_context + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_update_context(self, response: gcd_context.Context) -> gcd_context.Context: + """Post-rpc interceptor for update_context + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ContextsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ContextsRestInterceptor + + +class ContextsRestTransport(ContextsTransport): + """REST backend transport for Contexts. + + Service for managing [Contexts][google.cloud.dialogflow.v2.Context]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[ContextsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or ContextsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateContext(ContextsRestStub): + def __hash__(self): + return hash("CreateContext") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_context.CreateContextRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_context.Context: + r"""Call the create context method over HTTP. + + Args: + request (~.gcd_context.CreateContextRequest): + The request object. The request message for + [Contexts.CreateContext][google.cloud.dialogflow.v2.Contexts.CreateContext]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_context.Context: + Dialogflow contexts are similar to natural language + context. If a person says to you "they are orange", you + need context in order to understand what "they" is + referring to. Similarly, for Dialogflow to handle an + end-user expression like that, it needs to be provided + with context in order to correctly match an intent. + + Using contexts, you can control the flow of a + conversation. You can configure contexts for an intent + by setting input and output contexts, which are + identified by string names. When an intent is matched, + any configured output contexts for that intent become + active. While any contexts are active, Dialogflow is + more likely to match intents that are configured with + input contexts that correspond to the currently active + contexts. + + For more information about context, see the `Contexts + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent/sessions/*}/contexts", + "body": "context", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent/environments/*/users/*/sessions/*}/contexts", + "body": "context", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent/sessions/*}/contexts", + "body": "context", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent/environments/*/users/*/sessions/*}/contexts", + "body": "context", + }, + ] + request, metadata = self._interceptor.pre_create_context(request, metadata) + pb_request = gcd_context.CreateContextRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_context.Context() + pb_resp = gcd_context.Context.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_context(resp) + return resp + + class _DeleteAllContexts(ContextsRestStub): + def __hash__(self): + return hash("DeleteAllContexts") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: context.DeleteAllContextsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete all contexts method over HTTP. + + Args: + request (~.context.DeleteAllContextsRequest): + The request object. The request message for + [Contexts.DeleteAllContexts][google.cloud.dialogflow.v2.Contexts.DeleteAllContexts]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{parent=projects/*/agent/sessions/*}/contexts", + }, + { + "method": "delete", + "uri": "/v2/{parent=projects/*/agent/environments/*/users/*/sessions/*}/contexts", + }, + { + "method": "delete", + "uri": "/v2/{parent=projects/*/locations/*/agent/sessions/*}/contexts", + }, + { + "method": "delete", + "uri": "/v2/{parent=projects/*/locations/*/agent/environments/*/users/*/sessions/*}/contexts", + }, + ] + request, metadata = self._interceptor.pre_delete_all_contexts( + request, metadata + ) + pb_request = context.DeleteAllContextsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _DeleteContext(ContextsRestStub): + def __hash__(self): + return hash("DeleteContext") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: context.DeleteContextRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete context method over HTTP. + + Args: + request (~.context.DeleteContextRequest): + The request object. The request message for + [Contexts.DeleteContext][google.cloud.dialogflow.v2.Contexts.DeleteContext]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/agent/sessions/*/contexts/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/agent/environments/*/users/*/sessions/*/contexts/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/agent/sessions/*/contexts/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/contexts/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_context(request, metadata) + pb_request = context.DeleteContextRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetContext(ContextsRestStub): + def __hash__(self): + return hash("GetContext") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: context.GetContextRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> context.Context: + r"""Call the get context method over HTTP. + + Args: + request (~.context.GetContextRequest): + The request object. The request message for + [Contexts.GetContext][google.cloud.dialogflow.v2.Contexts.GetContext]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.context.Context: + Dialogflow contexts are similar to natural language + context. If a person says to you "they are orange", you + need context in order to understand what "they" is + referring to. Similarly, for Dialogflow to handle an + end-user expression like that, it needs to be provided + with context in order to correctly match an intent. + + Using contexts, you can control the flow of a + conversation. You can configure contexts for an intent + by setting input and output contexts, which are + identified by string names. When an intent is matched, + any configured output contexts for that intent become + active. While any contexts are active, Dialogflow is + more likely to match intents that are configured with + input contexts that correspond to the currently active + contexts. + + For more information about context, see the `Contexts + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/agent/sessions/*/contexts/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/agent/environments/*/users/*/sessions/*/contexts/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/agent/sessions/*/contexts/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/contexts/*}", + }, + ] + request, metadata = self._interceptor.pre_get_context(request, metadata) + pb_request = context.GetContextRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = context.Context() + pb_resp = context.Context.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_context(resp) + return resp + + class _ListContexts(ContextsRestStub): + def __hash__(self): + return hash("ListContexts") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: context.ListContextsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> context.ListContextsResponse: + r"""Call the list contexts method over HTTP. + + Args: + request (~.context.ListContextsRequest): + The request object. The request message for + [Contexts.ListContexts][google.cloud.dialogflow.v2.Contexts.ListContexts]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.context.ListContextsResponse: + The response message for + [Contexts.ListContexts][google.cloud.dialogflow.v2.Contexts.ListContexts]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent/sessions/*}/contexts", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent/environments/*/users/*/sessions/*}/contexts", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/agent/sessions/*}/contexts", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/agent/environments/*/users/*/sessions/*}/contexts", + }, + ] + request, metadata = self._interceptor.pre_list_contexts(request, metadata) + pb_request = context.ListContextsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = context.ListContextsResponse() + pb_resp = context.ListContextsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_contexts(resp) + return resp + + class _UpdateContext(ContextsRestStub): + def __hash__(self): + return hash("UpdateContext") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_context.UpdateContextRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_context.Context: + r"""Call the update context method over HTTP. + + Args: + request (~.gcd_context.UpdateContextRequest): + The request object. The request message for + [Contexts.UpdateContext][google.cloud.dialogflow.v2.Contexts.UpdateContext]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_context.Context: + Dialogflow contexts are similar to natural language + context. If a person says to you "they are orange", you + need context in order to understand what "they" is + referring to. Similarly, for Dialogflow to handle an + end-user expression like that, it needs to be provided + with context in order to correctly match an intent. + + Using contexts, you can control the flow of a + conversation. You can configure contexts for an intent + by setting input and output contexts, which are + identified by string names. When an intent is matched, + any configured output contexts for that intent become + active. While any contexts are active, Dialogflow is + more likely to match intents that are configured with + input contexts that correspond to the currently active + contexts. + + For more information about context, see the `Contexts + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{context.name=projects/*/agent/sessions/*/contexts/*}", + "body": "context", + }, + { + "method": "patch", + "uri": "/v2/{context.name=projects/*/agent/environments/*/users/*/sessions/*/contexts/*}", + "body": "context", + }, + { + "method": "patch", + "uri": "/v2/{context.name=projects/*/locations/*/agent/sessions/*/contexts/*}", + "body": "context", + }, + { + "method": "patch", + "uri": "/v2/{context.name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/contexts/*}", + "body": "context", + }, + ] + request, metadata = self._interceptor.pre_update_context(request, metadata) + pb_request = gcd_context.UpdateContextRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_context.Context() + pb_resp = gcd_context.Context.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_context(resp) + return resp + + @property + def create_context( + self, + ) -> Callable[[gcd_context.CreateContextRequest], gcd_context.Context]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateContext(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_all_contexts( + self, + ) -> Callable[[context.DeleteAllContextsRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteAllContexts(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_context( + self, + ) -> Callable[[context.DeleteContextRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteContext(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_context(self) -> Callable[[context.GetContextRequest], context.Context]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetContext(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_contexts( + self, + ) -> Callable[[context.ListContextsRequest], context.ListContextsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListContexts(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_context( + self, + ) -> Callable[[gcd_context.UpdateContextRequest], gcd_context.Context]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateContext(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ContextsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ContextsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ContextsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ContextsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ContextsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ContextsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/conversation_datasets/client.py b/google/cloud/dialogflow_v2/services/conversation_datasets/client.py index 6b009b27e..db27ba122 100644 --- a/google/cloud/dialogflow_v2/services/conversation_datasets/client.py +++ b/google/cloud/dialogflow_v2/services/conversation_datasets/client.py @@ -62,6 +62,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, ConversationDatasetsTransport from .transports.grpc import ConversationDatasetsGrpcTransport from .transports.grpc_asyncio import ConversationDatasetsGrpcAsyncIOTransport +from .transports.rest import ConversationDatasetsRestTransport class ConversationDatasetsClientMeta(type): @@ -77,6 +78,7 @@ class ConversationDatasetsClientMeta(type): ) # type: Dict[str, Type[ConversationDatasetsTransport]] _transport_registry["grpc"] = ConversationDatasetsGrpcTransport _transport_registry["grpc_asyncio"] = ConversationDatasetsGrpcAsyncIOTransport + _transport_registry["rest"] = ConversationDatasetsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/conversation_datasets/transports/__init__.py b/google/cloud/dialogflow_v2/services/conversation_datasets/transports/__init__.py index 6e5b2ac11..47c82aac6 100644 --- a/google/cloud/dialogflow_v2/services/conversation_datasets/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/conversation_datasets/transports/__init__.py @@ -19,6 +19,7 @@ from .base import ConversationDatasetsTransport from .grpc import ConversationDatasetsGrpcTransport from .grpc_asyncio import ConversationDatasetsGrpcAsyncIOTransport +from .rest import ConversationDatasetsRestInterceptor, ConversationDatasetsRestTransport # Compile a registry of transports. _transport_registry = ( @@ -26,9 +27,12 @@ ) # type: Dict[str, Type[ConversationDatasetsTransport]] _transport_registry["grpc"] = ConversationDatasetsGrpcTransport _transport_registry["grpc_asyncio"] = ConversationDatasetsGrpcAsyncIOTransport +_transport_registry["rest"] = ConversationDatasetsRestTransport __all__ = ( "ConversationDatasetsTransport", "ConversationDatasetsGrpcTransport", "ConversationDatasetsGrpcAsyncIOTransport", + "ConversationDatasetsRestTransport", + "ConversationDatasetsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/conversation_datasets/transports/rest.py b/google/cloud/dialogflow_v2/services/conversation_datasets/transports/rest.py new file mode 100644 index 000000000..d03cf6922 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/conversation_datasets/transports/rest.py @@ -0,0 +1,1429 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import ( + conversation_dataset as gcd_conversation_dataset, +) +from google.cloud.dialogflow_v2.types import conversation_dataset + +from .base import ConversationDatasetsTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class ConversationDatasetsRestInterceptor: + """Interceptor for ConversationDatasets. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the ConversationDatasetsRestTransport. + + .. code-block:: python + class MyCustomConversationDatasetsInterceptor(ConversationDatasetsRestInterceptor): + def pre_create_conversation_dataset(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_conversation_dataset(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_conversation_dataset(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_delete_conversation_dataset(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_conversation_dataset(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_conversation_dataset(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_import_conversation_data(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_import_conversation_data(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_conversation_datasets(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_conversation_datasets(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ConversationDatasetsRestTransport(interceptor=MyCustomConversationDatasetsInterceptor()) + client = ConversationDatasetsClient(transport=transport) + + + """ + + def pre_create_conversation_dataset( + self, + request: gcd_conversation_dataset.CreateConversationDatasetRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation_dataset.CreateConversationDatasetRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for create_conversation_dataset + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationDatasets server. + """ + return request, metadata + + def post_create_conversation_dataset( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for create_conversation_dataset + + Override in a subclass to manipulate the response + after it is returned by the ConversationDatasets server but before + it is returned to user code. + """ + return response + + def pre_delete_conversation_dataset( + self, + request: conversation_dataset.DeleteConversationDatasetRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_dataset.DeleteConversationDatasetRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for delete_conversation_dataset + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationDatasets server. + """ + return request, metadata + + def post_delete_conversation_dataset( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for delete_conversation_dataset + + Override in a subclass to manipulate the response + after it is returned by the ConversationDatasets server but before + it is returned to user code. + """ + return response + + def pre_get_conversation_dataset( + self, + request: conversation_dataset.GetConversationDatasetRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_dataset.GetConversationDatasetRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for get_conversation_dataset + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationDatasets server. + """ + return request, metadata + + def post_get_conversation_dataset( + self, response: conversation_dataset.ConversationDataset + ) -> conversation_dataset.ConversationDataset: + """Post-rpc interceptor for get_conversation_dataset + + Override in a subclass to manipulate the response + after it is returned by the ConversationDatasets server but before + it is returned to user code. + """ + return response + + def pre_import_conversation_data( + self, + request: conversation_dataset.ImportConversationDataRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_dataset.ImportConversationDataRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for import_conversation_data + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationDatasets server. + """ + return request, metadata + + def post_import_conversation_data( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for import_conversation_data + + Override in a subclass to manipulate the response + after it is returned by the ConversationDatasets server but before + it is returned to user code. + """ + return response + + def pre_list_conversation_datasets( + self, + request: conversation_dataset.ListConversationDatasetsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_dataset.ListConversationDatasetsRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for list_conversation_datasets + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationDatasets server. + """ + return request, metadata + + def post_list_conversation_datasets( + self, response: conversation_dataset.ListConversationDatasetsResponse + ) -> conversation_dataset.ListConversationDatasetsResponse: + """Post-rpc interceptor for list_conversation_datasets + + Override in a subclass to manipulate the response + after it is returned by the ConversationDatasets server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationDatasets server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the ConversationDatasets server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationDatasets server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the ConversationDatasets server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationDatasets server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the ConversationDatasets server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationDatasets server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the ConversationDatasets server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationDatasets server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the ConversationDatasets server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ConversationDatasetsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ConversationDatasetsRestInterceptor + + +class ConversationDatasetsRestTransport(ConversationDatasetsTransport): + """REST backend transport for ConversationDatasets. + + Conversation datasets. + Conversation datasets contain raw conversation files and their + customizable metadata that can be used for model training. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[ConversationDatasetsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or ConversationDatasetsRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CreateConversationDataset(ConversationDatasetsRestStub): + def __hash__(self): + return hash("CreateConversationDataset") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation_dataset.CreateConversationDatasetRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the create conversation + dataset method over HTTP. + + Args: + request (~.gcd_conversation_dataset.CreateConversationDatasetRequest): + The request object. The request message for + [ConversationDatasets.CreateConversationDataset][google.cloud.dialogflow.v2.ConversationDatasets.CreateConversationDataset]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*}/conversationDatasets", + "body": "conversation_dataset", + }, + ] + request, metadata = self._interceptor.pre_create_conversation_dataset( + request, metadata + ) + pb_request = gcd_conversation_dataset.CreateConversationDatasetRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_conversation_dataset(resp) + return resp + + class _DeleteConversationDataset(ConversationDatasetsRestStub): + def __hash__(self): + return hash("DeleteConversationDataset") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_dataset.DeleteConversationDatasetRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the delete conversation + dataset method over HTTP. + + Args: + request (~.conversation_dataset.DeleteConversationDatasetRequest): + The request object. The request message for + [ConversationDatasets.DeleteConversationDataset][google.cloud.dialogflow.v2.ConversationDatasets.DeleteConversationDataset]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/conversationDatasets/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_conversation_dataset( + request, metadata + ) + pb_request = conversation_dataset.DeleteConversationDatasetRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_delete_conversation_dataset(resp) + return resp + + class _GetConversationDataset(ConversationDatasetsRestStub): + def __hash__(self): + return hash("GetConversationDataset") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_dataset.GetConversationDatasetRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation_dataset.ConversationDataset: + r"""Call the get conversation dataset method over HTTP. + + Args: + request (~.conversation_dataset.GetConversationDatasetRequest): + The request object. The request message for + [ConversationDatasets.GetConversationDataset][google.cloud.dialogflow.v2.ConversationDatasets.GetConversationDataset]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation_dataset.ConversationDataset: + Represents a conversation dataset + that a user imports raw data into. The + data inside ConversationDataset can not + be changed after ImportConversationData + finishes (and calling + ImportConversationData on a dataset that + already has data is not allowed). + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/conversationDatasets/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/conversationDatasets/*}", + }, + ] + request, metadata = self._interceptor.pre_get_conversation_dataset( + request, metadata + ) + pb_request = conversation_dataset.GetConversationDatasetRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation_dataset.ConversationDataset() + pb_resp = conversation_dataset.ConversationDataset.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_conversation_dataset(resp) + return resp + + class _ImportConversationData(ConversationDatasetsRestStub): + def __hash__(self): + return hash("ImportConversationData") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_dataset.ImportConversationDataRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the import conversation data method over HTTP. + + Args: + request (~.conversation_dataset.ImportConversationDataRequest): + The request object. The request message for + [ConversationDatasets.ImportConversationData][google.cloud.dialogflow.v2.ConversationDatasets.ImportConversationData]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/conversationDatasets/*}:importConversationData", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/conversationDatasets/*}:importConversationData", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_import_conversation_data( + request, metadata + ) + pb_request = conversation_dataset.ImportConversationDataRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_import_conversation_data(resp) + return resp + + class _ListConversationDatasets(ConversationDatasetsRestStub): + def __hash__(self): + return hash("ListConversationDatasets") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_dataset.ListConversationDatasetsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation_dataset.ListConversationDatasetsResponse: + r"""Call the list conversation + datasets method over HTTP. + + Args: + request (~.conversation_dataset.ListConversationDatasetsRequest): + The request object. The request message for + [ConversationDatasets.ListConversationDatasets][google.cloud.dialogflow.v2.ConversationDatasets.ListConversationDatasets]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation_dataset.ListConversationDatasetsResponse: + The response message for + [ConversationDatasets.ListConversationDatasets][google.cloud.dialogflow.v2.ConversationDatasets.ListConversationDatasets]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*}/conversationDatasets", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*}/conversationDatasets", + }, + ] + request, metadata = self._interceptor.pre_list_conversation_datasets( + request, metadata + ) + pb_request = conversation_dataset.ListConversationDatasetsRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation_dataset.ListConversationDatasetsResponse() + pb_resp = conversation_dataset.ListConversationDatasetsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_conversation_datasets(resp) + return resp + + @property + def create_conversation_dataset( + self, + ) -> Callable[ + [gcd_conversation_dataset.CreateConversationDatasetRequest], + operations_pb2.Operation, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateConversationDataset(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_conversation_dataset( + self, + ) -> Callable[ + [conversation_dataset.DeleteConversationDatasetRequest], + operations_pb2.Operation, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteConversationDataset(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_conversation_dataset( + self, + ) -> Callable[ + [conversation_dataset.GetConversationDatasetRequest], + conversation_dataset.ConversationDataset, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetConversationDataset(self._session, self._host, self._interceptor) # type: ignore + + @property + def import_conversation_data( + self, + ) -> Callable[ + [conversation_dataset.ImportConversationDataRequest], operations_pb2.Operation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ImportConversationData(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_conversation_datasets( + self, + ) -> Callable[ + [conversation_dataset.ListConversationDatasetsRequest], + conversation_dataset.ListConversationDatasetsResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListConversationDatasets(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ConversationDatasetsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ConversationDatasetsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ConversationDatasetsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ConversationDatasetsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ConversationDatasetsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ConversationDatasetsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/conversation_models/client.py b/google/cloud/dialogflow_v2/services/conversation_models/client.py index a3d37fb80..21a4a17f7 100644 --- a/google/cloud/dialogflow_v2/services/conversation_models/client.py +++ b/google/cloud/dialogflow_v2/services/conversation_models/client.py @@ -62,6 +62,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, ConversationModelsTransport from .transports.grpc import ConversationModelsGrpcTransport from .transports.grpc_asyncio import ConversationModelsGrpcAsyncIOTransport +from .transports.rest import ConversationModelsRestTransport class ConversationModelsClientMeta(type): @@ -77,6 +78,7 @@ class ConversationModelsClientMeta(type): ) # type: Dict[str, Type[ConversationModelsTransport]] _transport_registry["grpc"] = ConversationModelsGrpcTransport _transport_registry["grpc_asyncio"] = ConversationModelsGrpcAsyncIOTransport + _transport_registry["rest"] = ConversationModelsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/conversation_models/transports/__init__.py b/google/cloud/dialogflow_v2/services/conversation_models/transports/__init__.py index da2f022f3..9d83aa7ed 100644 --- a/google/cloud/dialogflow_v2/services/conversation_models/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/conversation_models/transports/__init__.py @@ -19,6 +19,7 @@ from .base import ConversationModelsTransport from .grpc import ConversationModelsGrpcTransport from .grpc_asyncio import ConversationModelsGrpcAsyncIOTransport +from .rest import ConversationModelsRestInterceptor, ConversationModelsRestTransport # Compile a registry of transports. _transport_registry = ( @@ -26,9 +27,12 @@ ) # type: Dict[str, Type[ConversationModelsTransport]] _transport_registry["grpc"] = ConversationModelsGrpcTransport _transport_registry["grpc_asyncio"] = ConversationModelsGrpcAsyncIOTransport +_transport_registry["rest"] = ConversationModelsRestTransport __all__ = ( "ConversationModelsTransport", "ConversationModelsGrpcTransport", "ConversationModelsGrpcAsyncIOTransport", + "ConversationModelsRestTransport", + "ConversationModelsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/conversation_models/transports/rest.py b/google/cloud/dialogflow_v2/services/conversation_models/transports/rest.py new file mode 100644 index 000000000..1d4b9a76a --- /dev/null +++ b/google/cloud/dialogflow_v2/services/conversation_models/transports/rest.py @@ -0,0 +1,2013 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import ( + conversation_model as gcd_conversation_model, +) +from google.cloud.dialogflow_v2.types import conversation_model + +from .base import ConversationModelsTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class ConversationModelsRestInterceptor: + """Interceptor for ConversationModels. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the ConversationModelsRestTransport. + + .. code-block:: python + class MyCustomConversationModelsInterceptor(ConversationModelsRestInterceptor): + def pre_create_conversation_model(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_conversation_model(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_conversation_model_evaluation(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_conversation_model_evaluation(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_conversation_model(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_delete_conversation_model(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_deploy_conversation_model(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_deploy_conversation_model(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_conversation_model(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_conversation_model(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_conversation_model_evaluation(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_conversation_model_evaluation(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_conversation_model_evaluations(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_conversation_model_evaluations(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_conversation_models(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_conversation_models(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_undeploy_conversation_model(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_undeploy_conversation_model(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ConversationModelsRestTransport(interceptor=MyCustomConversationModelsInterceptor()) + client = ConversationModelsClient(transport=transport) + + + """ + + def pre_create_conversation_model( + self, + request: gcd_conversation_model.CreateConversationModelRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation_model.CreateConversationModelRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for create_conversation_model + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_create_conversation_model( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for create_conversation_model + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_create_conversation_model_evaluation( + self, + request: conversation_model.CreateConversationModelEvaluationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_model.CreateConversationModelEvaluationRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for create_conversation_model_evaluation + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_create_conversation_model_evaluation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for create_conversation_model_evaluation + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_delete_conversation_model( + self, + request: conversation_model.DeleteConversationModelRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_model.DeleteConversationModelRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for delete_conversation_model + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_delete_conversation_model( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for delete_conversation_model + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_deploy_conversation_model( + self, + request: conversation_model.DeployConversationModelRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_model.DeployConversationModelRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for deploy_conversation_model + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_deploy_conversation_model( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for deploy_conversation_model + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_get_conversation_model( + self, + request: conversation_model.GetConversationModelRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_model.GetConversationModelRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for get_conversation_model + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_get_conversation_model( + self, response: conversation_model.ConversationModel + ) -> conversation_model.ConversationModel: + """Post-rpc interceptor for get_conversation_model + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_get_conversation_model_evaluation( + self, + request: conversation_model.GetConversationModelEvaluationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_model.GetConversationModelEvaluationRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for get_conversation_model_evaluation + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_get_conversation_model_evaluation( + self, response: conversation_model.ConversationModelEvaluation + ) -> conversation_model.ConversationModelEvaluation: + """Post-rpc interceptor for get_conversation_model_evaluation + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_list_conversation_model_evaluations( + self, + request: conversation_model.ListConversationModelEvaluationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_model.ListConversationModelEvaluationsRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for list_conversation_model_evaluations + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_list_conversation_model_evaluations( + self, response: conversation_model.ListConversationModelEvaluationsResponse + ) -> conversation_model.ListConversationModelEvaluationsResponse: + """Post-rpc interceptor for list_conversation_model_evaluations + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_list_conversation_models( + self, + request: conversation_model.ListConversationModelsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_model.ListConversationModelsRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for list_conversation_models + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_list_conversation_models( + self, response: conversation_model.ListConversationModelsResponse + ) -> conversation_model.ListConversationModelsResponse: + """Post-rpc interceptor for list_conversation_models + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_undeploy_conversation_model( + self, + request: conversation_model.UndeployConversationModelRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_model.UndeployConversationModelRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for undeploy_conversation_model + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_undeploy_conversation_model( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for undeploy_conversation_model + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationModels server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the ConversationModels server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ConversationModelsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ConversationModelsRestInterceptor + + +class ConversationModelsRestTransport(ConversationModelsTransport): + """REST backend transport for ConversationModels. + + Manages a collection of models for human agent assistant. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[ConversationModelsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or ConversationModelsRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CreateConversationModel(ConversationModelsRestStub): + def __hash__(self): + return hash("CreateConversationModel") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation_model.CreateConversationModelRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the create conversation model method over HTTP. + + Args: + request (~.gcd_conversation_model.CreateConversationModelRequest): + The request object. The request message for + [ConversationModels.CreateConversationModel][google.cloud.dialogflow.v2.ConversationModels.CreateConversationModel] + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*}/conversationModels", + "body": "conversation_model", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*}/conversationModels", + "body": "conversation_model", + }, + ] + request, metadata = self._interceptor.pre_create_conversation_model( + request, metadata + ) + pb_request = gcd_conversation_model.CreateConversationModelRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_conversation_model(resp) + return resp + + class _CreateConversationModelEvaluation(ConversationModelsRestStub): + def __hash__(self): + return hash("CreateConversationModelEvaluation") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_model.CreateConversationModelEvaluationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the create conversation model + evaluation method over HTTP. + + Args: + request (~.conversation_model.CreateConversationModelEvaluationRequest): + The request object. The request message for + [ConversationModels.CreateConversationModelEvaluation][google.cloud.dialogflow.v2.ConversationModels.CreateConversationModelEvaluation] + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/conversationModels/*}/evaluations", + "body": "*", + }, + ] + ( + request, + metadata, + ) = self._interceptor.pre_create_conversation_model_evaluation( + request, metadata + ) + pb_request = conversation_model.CreateConversationModelEvaluationRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_conversation_model_evaluation(resp) + return resp + + class _DeleteConversationModel(ConversationModelsRestStub): + def __hash__(self): + return hash("DeleteConversationModel") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_model.DeleteConversationModelRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the delete conversation model method over HTTP. + + Args: + request (~.conversation_model.DeleteConversationModelRequest): + The request object. The request message for + [ConversationModels.DeleteConversationModel][google.cloud.dialogflow.v2.ConversationModels.DeleteConversationModel] + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/conversationModels/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/conversationModels/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_conversation_model( + request, metadata + ) + pb_request = conversation_model.DeleteConversationModelRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_delete_conversation_model(resp) + return resp + + class _DeployConversationModel(ConversationModelsRestStub): + def __hash__(self): + return hash("DeployConversationModel") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_model.DeployConversationModelRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the deploy conversation model method over HTTP. + + Args: + request (~.conversation_model.DeployConversationModelRequest): + The request object. The request message for + [ConversationModels.DeployConversationModel][google.cloud.dialogflow.v2.ConversationModels.DeployConversationModel] + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/conversationModels/*}:deploy", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/conversationModels/*}:deploy", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_deploy_conversation_model( + request, metadata + ) + pb_request = conversation_model.DeployConversationModelRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_deploy_conversation_model(resp) + return resp + + class _GetConversationModel(ConversationModelsRestStub): + def __hash__(self): + return hash("GetConversationModel") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_model.GetConversationModelRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation_model.ConversationModel: + r"""Call the get conversation model method over HTTP. + + Args: + request (~.conversation_model.GetConversationModelRequest): + The request object. The request message for + [ConversationModels.GetConversationModel][google.cloud.dialogflow.v2.ConversationModels.GetConversationModel] + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation_model.ConversationModel: + Represents a conversation model. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/conversationModels/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/conversationModels/*}", + }, + ] + request, metadata = self._interceptor.pre_get_conversation_model( + request, metadata + ) + pb_request = conversation_model.GetConversationModelRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation_model.ConversationModel() + pb_resp = conversation_model.ConversationModel.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_conversation_model(resp) + return resp + + class _GetConversationModelEvaluation(ConversationModelsRestStub): + def __hash__(self): + return hash("GetConversationModelEvaluation") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_model.GetConversationModelEvaluationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation_model.ConversationModelEvaluation: + r"""Call the get conversation model + evaluation method over HTTP. + + Args: + request (~.conversation_model.GetConversationModelEvaluationRequest): + The request object. The request message for + [ConversationModels.GetConversationModelEvaluation][google.cloud.dialogflow.v2.ConversationModels.GetConversationModelEvaluation] + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation_model.ConversationModelEvaluation: + Represents evaluation result of a + conversation model. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/conversationModels/*/evaluations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/conversationModels/*/evaluations/*}", + }, + ] + request, metadata = self._interceptor.pre_get_conversation_model_evaluation( + request, metadata + ) + pb_request = conversation_model.GetConversationModelEvaluationRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation_model.ConversationModelEvaluation() + pb_resp = conversation_model.ConversationModelEvaluation.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_conversation_model_evaluation(resp) + return resp + + class _ListConversationModelEvaluations(ConversationModelsRestStub): + def __hash__(self): + return hash("ListConversationModelEvaluations") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_model.ListConversationModelEvaluationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation_model.ListConversationModelEvaluationsResponse: + r"""Call the list conversation model + evaluations method over HTTP. + + Args: + request (~.conversation_model.ListConversationModelEvaluationsRequest): + The request object. The request message for + [ConversationModels.ListConversationModelEvaluations][google.cloud.dialogflow.v2.ConversationModels.ListConversationModelEvaluations] + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation_model.ListConversationModelEvaluationsResponse: + The response message for + [ConversationModels.ListConversationModelEvaluations][google.cloud.dialogflow.v2.ConversationModels.ListConversationModelEvaluations] + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/conversationModels/*}/evaluations", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/conversationModels/*}/evaluations", + }, + ] + ( + request, + metadata, + ) = self._interceptor.pre_list_conversation_model_evaluations( + request, metadata + ) + pb_request = conversation_model.ListConversationModelEvaluationsRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation_model.ListConversationModelEvaluationsResponse() + pb_resp = conversation_model.ListConversationModelEvaluationsResponse.pb( + resp + ) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_conversation_model_evaluations(resp) + return resp + + class _ListConversationModels(ConversationModelsRestStub): + def __hash__(self): + return hash("ListConversationModels") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_model.ListConversationModelsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation_model.ListConversationModelsResponse: + r"""Call the list conversation models method over HTTP. + + Args: + request (~.conversation_model.ListConversationModelsRequest): + The request object. The request message for + [ConversationModels.ListConversationModels][google.cloud.dialogflow.v2.ConversationModels.ListConversationModels] + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation_model.ListConversationModelsResponse: + The response message for + [ConversationModels.ListConversationModels][google.cloud.dialogflow.v2.ConversationModels.ListConversationModels] + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*}/conversationModels", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*}/conversationModels", + }, + ] + request, metadata = self._interceptor.pre_list_conversation_models( + request, metadata + ) + pb_request = conversation_model.ListConversationModelsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation_model.ListConversationModelsResponse() + pb_resp = conversation_model.ListConversationModelsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_conversation_models(resp) + return resp + + class _UndeployConversationModel(ConversationModelsRestStub): + def __hash__(self): + return hash("UndeployConversationModel") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_model.UndeployConversationModelRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the undeploy conversation + model method over HTTP. + + Args: + request (~.conversation_model.UndeployConversationModelRequest): + The request object. The request message for + [ConversationModels.UndeployConversationModel][google.cloud.dialogflow.v2.ConversationModels.UndeployConversationModel] + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/conversationModels/*}:undeploy", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/conversationModels/*}:undeploy", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_undeploy_conversation_model( + request, metadata + ) + pb_request = conversation_model.UndeployConversationModelRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_undeploy_conversation_model(resp) + return resp + + @property + def create_conversation_model( + self, + ) -> Callable[ + [gcd_conversation_model.CreateConversationModelRequest], + operations_pb2.Operation, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateConversationModel(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_conversation_model_evaluation( + self, + ) -> Callable[ + [conversation_model.CreateConversationModelEvaluationRequest], + operations_pb2.Operation, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateConversationModelEvaluation(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_conversation_model( + self, + ) -> Callable[ + [conversation_model.DeleteConversationModelRequest], operations_pb2.Operation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteConversationModel(self._session, self._host, self._interceptor) # type: ignore + + @property + def deploy_conversation_model( + self, + ) -> Callable[ + [conversation_model.DeployConversationModelRequest], operations_pb2.Operation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeployConversationModel(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_conversation_model( + self, + ) -> Callable[ + [conversation_model.GetConversationModelRequest], + conversation_model.ConversationModel, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetConversationModel(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_conversation_model_evaluation( + self, + ) -> Callable[ + [conversation_model.GetConversationModelEvaluationRequest], + conversation_model.ConversationModelEvaluation, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetConversationModelEvaluation(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_conversation_model_evaluations( + self, + ) -> Callable[ + [conversation_model.ListConversationModelEvaluationsRequest], + conversation_model.ListConversationModelEvaluationsResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListConversationModelEvaluations(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_conversation_models( + self, + ) -> Callable[ + [conversation_model.ListConversationModelsRequest], + conversation_model.ListConversationModelsResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListConversationModels(self._session, self._host, self._interceptor) # type: ignore + + @property + def undeploy_conversation_model( + self, + ) -> Callable[ + [conversation_model.UndeployConversationModelRequest], operations_pb2.Operation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UndeployConversationModel(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ConversationModelsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ConversationModelsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ConversationModelsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ConversationModelsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ConversationModelsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ConversationModelsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/conversation_profiles/client.py b/google/cloud/dialogflow_v2/services/conversation_profiles/client.py index a84f272ad..becf8a4b1 100644 --- a/google/cloud/dialogflow_v2/services/conversation_profiles/client.py +++ b/google/cloud/dialogflow_v2/services/conversation_profiles/client.py @@ -63,6 +63,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, ConversationProfilesTransport from .transports.grpc import ConversationProfilesGrpcTransport from .transports.grpc_asyncio import ConversationProfilesGrpcAsyncIOTransport +from .transports.rest import ConversationProfilesRestTransport class ConversationProfilesClientMeta(type): @@ -78,6 +79,7 @@ class ConversationProfilesClientMeta(type): ) # type: Dict[str, Type[ConversationProfilesTransport]] _transport_registry["grpc"] = ConversationProfilesGrpcTransport _transport_registry["grpc_asyncio"] = ConversationProfilesGrpcAsyncIOTransport + _transport_registry["rest"] = ConversationProfilesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/conversation_profiles/transports/__init__.py b/google/cloud/dialogflow_v2/services/conversation_profiles/transports/__init__.py index 969f74511..539a27c22 100644 --- a/google/cloud/dialogflow_v2/services/conversation_profiles/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/conversation_profiles/transports/__init__.py @@ -19,6 +19,7 @@ from .base import ConversationProfilesTransport from .grpc import ConversationProfilesGrpcTransport from .grpc_asyncio import ConversationProfilesGrpcAsyncIOTransport +from .rest import ConversationProfilesRestInterceptor, ConversationProfilesRestTransport # Compile a registry of transports. _transport_registry = ( @@ -26,9 +27,12 @@ ) # type: Dict[str, Type[ConversationProfilesTransport]] _transport_registry["grpc"] = ConversationProfilesGrpcTransport _transport_registry["grpc_asyncio"] = ConversationProfilesGrpcAsyncIOTransport +_transport_registry["rest"] = ConversationProfilesRestTransport __all__ = ( "ConversationProfilesTransport", "ConversationProfilesGrpcTransport", "ConversationProfilesGrpcAsyncIOTransport", + "ConversationProfilesRestTransport", + "ConversationProfilesRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/conversation_profiles/transports/rest.py b/google/cloud/dialogflow_v2/services/conversation_profiles/transports/rest.py new file mode 100644 index 000000000..8cdff3869 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/conversation_profiles/transports/rest.py @@ -0,0 +1,1722 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import ( + conversation_profile as gcd_conversation_profile, +) +from google.cloud.dialogflow_v2.types import conversation_profile + +from .base import ConversationProfilesTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class ConversationProfilesRestInterceptor: + """Interceptor for ConversationProfiles. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the ConversationProfilesRestTransport. + + .. code-block:: python + class MyCustomConversationProfilesInterceptor(ConversationProfilesRestInterceptor): + def pre_clear_suggestion_feature_config(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_clear_suggestion_feature_config(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_conversation_profile(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_conversation_profile(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_conversation_profile(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_conversation_profile(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_conversation_profile(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_conversation_profiles(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_conversation_profiles(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_set_suggestion_feature_config(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_set_suggestion_feature_config(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_conversation_profile(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_conversation_profile(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ConversationProfilesRestTransport(interceptor=MyCustomConversationProfilesInterceptor()) + client = ConversationProfilesClient(transport=transport) + + + """ + + def pre_clear_suggestion_feature_config( + self, + request: gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for clear_suggestion_feature_config + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_clear_suggestion_feature_config( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for clear_suggestion_feature_config + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_create_conversation_profile( + self, + request: gcd_conversation_profile.CreateConversationProfileRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation_profile.CreateConversationProfileRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for create_conversation_profile + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_create_conversation_profile( + self, response: gcd_conversation_profile.ConversationProfile + ) -> gcd_conversation_profile.ConversationProfile: + """Post-rpc interceptor for create_conversation_profile + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_delete_conversation_profile( + self, + request: conversation_profile.DeleteConversationProfileRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_profile.DeleteConversationProfileRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for delete_conversation_profile + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def pre_get_conversation_profile( + self, + request: conversation_profile.GetConversationProfileRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_profile.GetConversationProfileRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for get_conversation_profile + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_get_conversation_profile( + self, response: conversation_profile.ConversationProfile + ) -> conversation_profile.ConversationProfile: + """Post-rpc interceptor for get_conversation_profile + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_list_conversation_profiles( + self, + request: conversation_profile.ListConversationProfilesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_profile.ListConversationProfilesRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for list_conversation_profiles + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_list_conversation_profiles( + self, response: conversation_profile.ListConversationProfilesResponse + ) -> conversation_profile.ListConversationProfilesResponse: + """Post-rpc interceptor for list_conversation_profiles + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_set_suggestion_feature_config( + self, + request: gcd_conversation_profile.SetSuggestionFeatureConfigRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation_profile.SetSuggestionFeatureConfigRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for set_suggestion_feature_config + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_set_suggestion_feature_config( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for set_suggestion_feature_config + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_update_conversation_profile( + self, + request: gcd_conversation_profile.UpdateConversationProfileRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation_profile.UpdateConversationProfileRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for update_conversation_profile + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_update_conversation_profile( + self, response: gcd_conversation_profile.ConversationProfile + ) -> gcd_conversation_profile.ConversationProfile: + """Post-rpc interceptor for update_conversation_profile + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ConversationProfilesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ConversationProfilesRestInterceptor + + +class ConversationProfilesRestTransport(ConversationProfilesTransport): + """REST backend transport for ConversationProfiles. + + Service for managing + [ConversationProfiles][google.cloud.dialogflow.v2.ConversationProfile]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[ConversationProfilesRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or ConversationProfilesRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _ClearSuggestionFeatureConfig(ConversationProfilesRestStub): + def __hash__(self): + return hash("ClearSuggestionFeatureConfig") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the clear suggestion feature + config method over HTTP. + + Args: + request (~.gcd_conversation_profile.ClearSuggestionFeatureConfigRequest): + The request object. The request message for + [ConversationProfiles.ClearFeature][]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{conversation_profile=projects/*/conversationProfiles/*}:clearSuggestionFeatureConfig", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{conversation_profile=projects/*/locations/*/conversationProfiles/*}:clearSuggestionFeatureConfig", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_clear_suggestion_feature_config( + request, metadata + ) + pb_request = ( + gcd_conversation_profile.ClearSuggestionFeatureConfigRequest.pb(request) + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_clear_suggestion_feature_config(resp) + return resp + + class _CreateConversationProfile(ConversationProfilesRestStub): + def __hash__(self): + return hash("CreateConversationProfile") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation_profile.CreateConversationProfileRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_conversation_profile.ConversationProfile: + r"""Call the create conversation + profile method over HTTP. + + Args: + request (~.gcd_conversation_profile.CreateConversationProfileRequest): + The request object. The request message for + [ConversationProfiles.CreateConversationProfile][google.cloud.dialogflow.v2.ConversationProfiles.CreateConversationProfile]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_conversation_profile.ConversationProfile: + Defines the services to connect to + incoming Dialogflow conversations. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*}/conversationProfiles", + "body": "conversation_profile", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*}/conversationProfiles", + "body": "conversation_profile", + }, + ] + request, metadata = self._interceptor.pre_create_conversation_profile( + request, metadata + ) + pb_request = gcd_conversation_profile.CreateConversationProfileRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_conversation_profile.ConversationProfile() + pb_resp = gcd_conversation_profile.ConversationProfile.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_conversation_profile(resp) + return resp + + class _DeleteConversationProfile(ConversationProfilesRestStub): + def __hash__(self): + return hash("DeleteConversationProfile") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_profile.DeleteConversationProfileRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete conversation + profile method over HTTP. + + Args: + request (~.conversation_profile.DeleteConversationProfileRequest): + The request object. The request message for + [ConversationProfiles.DeleteConversationProfile][google.cloud.dialogflow.v2.ConversationProfiles.DeleteConversationProfile]. + + This operation fails if the conversation profile is + still referenced from a phone number. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/conversationProfiles/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/conversationProfiles/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_conversation_profile( + request, metadata + ) + pb_request = conversation_profile.DeleteConversationProfileRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetConversationProfile(ConversationProfilesRestStub): + def __hash__(self): + return hash("GetConversationProfile") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_profile.GetConversationProfileRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation_profile.ConversationProfile: + r"""Call the get conversation profile method over HTTP. + + Args: + request (~.conversation_profile.GetConversationProfileRequest): + The request object. The request message for + [ConversationProfiles.GetConversationProfile][google.cloud.dialogflow.v2.ConversationProfiles.GetConversationProfile]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation_profile.ConversationProfile: + Defines the services to connect to + incoming Dialogflow conversations. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/conversationProfiles/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/conversationProfiles/*}", + }, + ] + request, metadata = self._interceptor.pre_get_conversation_profile( + request, metadata + ) + pb_request = conversation_profile.GetConversationProfileRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation_profile.ConversationProfile() + pb_resp = conversation_profile.ConversationProfile.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_conversation_profile(resp) + return resp + + class _ListConversationProfiles(ConversationProfilesRestStub): + def __hash__(self): + return hash("ListConversationProfiles") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_profile.ListConversationProfilesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation_profile.ListConversationProfilesResponse: + r"""Call the list conversation + profiles method over HTTP. + + Args: + request (~.conversation_profile.ListConversationProfilesRequest): + The request object. The request message for + [ConversationProfiles.ListConversationProfiles][google.cloud.dialogflow.v2.ConversationProfiles.ListConversationProfiles]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation_profile.ListConversationProfilesResponse: + The response message for + [ConversationProfiles.ListConversationProfiles][google.cloud.dialogflow.v2.ConversationProfiles.ListConversationProfiles]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*}/conversationProfiles", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*}/conversationProfiles", + }, + ] + request, metadata = self._interceptor.pre_list_conversation_profiles( + request, metadata + ) + pb_request = conversation_profile.ListConversationProfilesRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation_profile.ListConversationProfilesResponse() + pb_resp = conversation_profile.ListConversationProfilesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_conversation_profiles(resp) + return resp + + class _SetSuggestionFeatureConfig(ConversationProfilesRestStub): + def __hash__(self): + return hash("SetSuggestionFeatureConfig") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation_profile.SetSuggestionFeatureConfigRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the set suggestion feature + config method over HTTP. + + Args: + request (~.gcd_conversation_profile.SetSuggestionFeatureConfigRequest): + The request object. The request message for + [ConversationProfiles.SetSuggestionFeature][]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{conversation_profile=projects/*/conversationProfiles/*}:setSuggestionFeatureConfig", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{conversation_profile=projects/*/locations/*/conversationProfiles/*}:setSuggestionFeatureConfig", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_set_suggestion_feature_config( + request, metadata + ) + pb_request = gcd_conversation_profile.SetSuggestionFeatureConfigRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_set_suggestion_feature_config(resp) + return resp + + class _UpdateConversationProfile(ConversationProfilesRestStub): + def __hash__(self): + return hash("UpdateConversationProfile") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation_profile.UpdateConversationProfileRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_conversation_profile.ConversationProfile: + r"""Call the update conversation + profile method over HTTP. + + Args: + request (~.gcd_conversation_profile.UpdateConversationProfileRequest): + The request object. The request message for + [ConversationProfiles.UpdateConversationProfile][google.cloud.dialogflow.v2.ConversationProfiles.UpdateConversationProfile]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_conversation_profile.ConversationProfile: + Defines the services to connect to + incoming Dialogflow conversations. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{conversation_profile.name=projects/*/conversationProfiles/*}", + "body": "conversation_profile", + }, + { + "method": "patch", + "uri": "/v2/{conversation_profile.name=projects/*/locations/*/conversationProfiles/*}", + "body": "conversation_profile", + }, + ] + request, metadata = self._interceptor.pre_update_conversation_profile( + request, metadata + ) + pb_request = gcd_conversation_profile.UpdateConversationProfileRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_conversation_profile.ConversationProfile() + pb_resp = gcd_conversation_profile.ConversationProfile.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_conversation_profile(resp) + return resp + + @property + def clear_suggestion_feature_config( + self, + ) -> Callable[ + [gcd_conversation_profile.ClearSuggestionFeatureConfigRequest], + operations_pb2.Operation, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ClearSuggestionFeatureConfig(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_conversation_profile( + self, + ) -> Callable[ + [gcd_conversation_profile.CreateConversationProfileRequest], + gcd_conversation_profile.ConversationProfile, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateConversationProfile(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_conversation_profile( + self, + ) -> Callable[ + [conversation_profile.DeleteConversationProfileRequest], empty_pb2.Empty + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteConversationProfile(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_conversation_profile( + self, + ) -> Callable[ + [conversation_profile.GetConversationProfileRequest], + conversation_profile.ConversationProfile, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetConversationProfile(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_conversation_profiles( + self, + ) -> Callable[ + [conversation_profile.ListConversationProfilesRequest], + conversation_profile.ListConversationProfilesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListConversationProfiles(self._session, self._host, self._interceptor) # type: ignore + + @property + def set_suggestion_feature_config( + self, + ) -> Callable[ + [gcd_conversation_profile.SetSuggestionFeatureConfigRequest], + operations_pb2.Operation, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SetSuggestionFeatureConfig(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_conversation_profile( + self, + ) -> Callable[ + [gcd_conversation_profile.UpdateConversationProfileRequest], + gcd_conversation_profile.ConversationProfile, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateConversationProfile(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ConversationProfilesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ConversationProfilesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ConversationProfilesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ConversationProfilesRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ConversationProfilesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ConversationProfilesRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/conversations/client.py b/google/cloud/dialogflow_v2/services/conversations/client.py index 854cc7f52..3c4d75083 100644 --- a/google/cloud/dialogflow_v2/services/conversations/client.py +++ b/google/cloud/dialogflow_v2/services/conversations/client.py @@ -58,6 +58,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, ConversationsTransport from .transports.grpc import ConversationsGrpcTransport from .transports.grpc_asyncio import ConversationsGrpcAsyncIOTransport +from .transports.rest import ConversationsRestTransport class ConversationsClientMeta(type): @@ -71,6 +72,7 @@ class ConversationsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[ConversationsTransport]] _transport_registry["grpc"] = ConversationsGrpcTransport _transport_registry["grpc_asyncio"] = ConversationsGrpcAsyncIOTransport + _transport_registry["rest"] = ConversationsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/conversations/transports/__init__.py b/google/cloud/dialogflow_v2/services/conversations/transports/__init__.py index 4124c89ab..1b2e228b6 100644 --- a/google/cloud/dialogflow_v2/services/conversations/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/conversations/transports/__init__.py @@ -19,14 +19,18 @@ from .base import ConversationsTransport from .grpc import ConversationsGrpcTransport from .grpc_asyncio import ConversationsGrpcAsyncIOTransport +from .rest import ConversationsRestInterceptor, ConversationsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[ConversationsTransport]] _transport_registry["grpc"] = ConversationsGrpcTransport _transport_registry["grpc_asyncio"] = ConversationsGrpcAsyncIOTransport +_transport_registry["rest"] = ConversationsRestTransport __all__ = ( "ConversationsTransport", "ConversationsGrpcTransport", "ConversationsGrpcAsyncIOTransport", + "ConversationsRestTransport", + "ConversationsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/conversations/transports/rest.py b/google/cloud/dialogflow_v2/services/conversations/transports/rest.py new file mode 100644 index 000000000..f08c20ff0 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/conversations/transports/rest.py @@ -0,0 +1,1504 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.dialogflow_v2.types import conversation +from google.cloud.dialogflow_v2.types import conversation as gcd_conversation + +from .base import ConversationsTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class ConversationsRestInterceptor: + """Interceptor for Conversations. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the ConversationsRestTransport. + + .. code-block:: python + class MyCustomConversationsInterceptor(ConversationsRestInterceptor): + def pre_complete_conversation(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_complete_conversation(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_conversation(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_conversation(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_conversation(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_conversation(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_conversations(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_conversations(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_messages(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_messages(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_suggest_conversation_summary(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_suggest_conversation_summary(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ConversationsRestTransport(interceptor=MyCustomConversationsInterceptor()) + client = ConversationsClient(transport=transport) + + + """ + + def pre_complete_conversation( + self, + request: conversation.CompleteConversationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[conversation.CompleteConversationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for complete_conversation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_complete_conversation( + self, response: conversation.Conversation + ) -> conversation.Conversation: + """Post-rpc interceptor for complete_conversation + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_create_conversation( + self, + request: gcd_conversation.CreateConversationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_conversation.CreateConversationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_conversation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_create_conversation( + self, response: gcd_conversation.Conversation + ) -> gcd_conversation.Conversation: + """Post-rpc interceptor for create_conversation + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_get_conversation( + self, + request: conversation.GetConversationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[conversation.GetConversationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_conversation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_get_conversation( + self, response: conversation.Conversation + ) -> conversation.Conversation: + """Post-rpc interceptor for get_conversation + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_list_conversations( + self, + request: conversation.ListConversationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[conversation.ListConversationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_conversations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_list_conversations( + self, response: conversation.ListConversationsResponse + ) -> conversation.ListConversationsResponse: + """Post-rpc interceptor for list_conversations + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_list_messages( + self, + request: conversation.ListMessagesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[conversation.ListMessagesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_messages + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_list_messages( + self, response: conversation.ListMessagesResponse + ) -> conversation.ListMessagesResponse: + """Post-rpc interceptor for list_messages + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_suggest_conversation_summary( + self, + request: gcd_conversation.SuggestConversationSummaryRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation.SuggestConversationSummaryRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for suggest_conversation_summary + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_suggest_conversation_summary( + self, response: gcd_conversation.SuggestConversationSummaryResponse + ) -> gcd_conversation.SuggestConversationSummaryResponse: + """Post-rpc interceptor for suggest_conversation_summary + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ConversationsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ConversationsRestInterceptor + + +class ConversationsRestTransport(ConversationsTransport): + """REST backend transport for Conversations. + + Service for managing + [Conversations][google.cloud.dialogflow.v2.Conversation]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[ConversationsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or ConversationsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CompleteConversation(ConversationsRestStub): + def __hash__(self): + return hash("CompleteConversation") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation.CompleteConversationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation.Conversation: + r"""Call the complete conversation method over HTTP. + + Args: + request (~.conversation.CompleteConversationRequest): + The request object. The request message for + [Conversations.CompleteConversation][google.cloud.dialogflow.v2.Conversations.CompleteConversation]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation.Conversation: + Represents a conversation. + A conversation is an interaction between + an agent, including live agents and + Dialogflow agents, and a support + customer. Conversations can include + phone calls and text-based chat + sessions. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/conversations/*}:complete", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/conversations/*}:complete", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_complete_conversation( + request, metadata + ) + pb_request = conversation.CompleteConversationRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation.Conversation() + pb_resp = conversation.Conversation.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_complete_conversation(resp) + return resp + + class _CreateConversation(ConversationsRestStub): + def __hash__(self): + return hash("CreateConversation") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation.CreateConversationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_conversation.Conversation: + r"""Call the create conversation method over HTTP. + + Args: + request (~.gcd_conversation.CreateConversationRequest): + The request object. The request message for + [Conversations.CreateConversation][google.cloud.dialogflow.v2.Conversations.CreateConversation]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_conversation.Conversation: + Represents a conversation. + A conversation is an interaction between + an agent, including live agents and + Dialogflow agents, and a support + customer. Conversations can include + phone calls and text-based chat + sessions. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*}/conversations", + "body": "conversation", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*}/conversations", + "body": "conversation", + }, + ] + request, metadata = self._interceptor.pre_create_conversation( + request, metadata + ) + pb_request = gcd_conversation.CreateConversationRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_conversation.Conversation() + pb_resp = gcd_conversation.Conversation.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_conversation(resp) + return resp + + class _GetConversation(ConversationsRestStub): + def __hash__(self): + return hash("GetConversation") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation.GetConversationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation.Conversation: + r"""Call the get conversation method over HTTP. + + Args: + request (~.conversation.GetConversationRequest): + The request object. The request message for + [Conversations.GetConversation][google.cloud.dialogflow.v2.Conversations.GetConversation]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation.Conversation: + Represents a conversation. + A conversation is an interaction between + an agent, including live agents and + Dialogflow agents, and a support + customer. Conversations can include + phone calls and text-based chat + sessions. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/conversations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/conversations/*}", + }, + ] + request, metadata = self._interceptor.pre_get_conversation( + request, metadata + ) + pb_request = conversation.GetConversationRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation.Conversation() + pb_resp = conversation.Conversation.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_conversation(resp) + return resp + + class _ListConversations(ConversationsRestStub): + def __hash__(self): + return hash("ListConversations") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation.ListConversationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation.ListConversationsResponse: + r"""Call the list conversations method over HTTP. + + Args: + request (~.conversation.ListConversationsRequest): + The request object. The request message for + [Conversations.ListConversations][google.cloud.dialogflow.v2.Conversations.ListConversations]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation.ListConversationsResponse: + The response message for + [Conversations.ListConversations][google.cloud.dialogflow.v2.Conversations.ListConversations]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*}/conversations", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*}/conversations", + }, + ] + request, metadata = self._interceptor.pre_list_conversations( + request, metadata + ) + pb_request = conversation.ListConversationsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation.ListConversationsResponse() + pb_resp = conversation.ListConversationsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_conversations(resp) + return resp + + class _ListMessages(ConversationsRestStub): + def __hash__(self): + return hash("ListMessages") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation.ListMessagesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation.ListMessagesResponse: + r"""Call the list messages method over HTTP. + + Args: + request (~.conversation.ListMessagesRequest): + The request object. The request message for + [Conversations.ListMessages][google.cloud.dialogflow.v2.Conversations.ListMessages]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation.ListMessagesResponse: + The response message for + [Conversations.ListMessages][google.cloud.dialogflow.v2.Conversations.ListMessages]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/conversations/*}/messages", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/conversations/*}/messages", + }, + ] + request, metadata = self._interceptor.pre_list_messages(request, metadata) + pb_request = conversation.ListMessagesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation.ListMessagesResponse() + pb_resp = conversation.ListMessagesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_messages(resp) + return resp + + class _SuggestConversationSummary(ConversationsRestStub): + def __hash__(self): + return hash("SuggestConversationSummary") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation.SuggestConversationSummaryRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_conversation.SuggestConversationSummaryResponse: + r"""Call the suggest conversation + summary method over HTTP. + + Args: + request (~.gcd_conversation.SuggestConversationSummaryRequest): + The request object. The request message for + [Conversations.SuggestConversationSummary][google.cloud.dialogflow.v2.Conversations.SuggestConversationSummary]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_conversation.SuggestConversationSummaryResponse: + The response message for + [Conversations.SuggestConversationSummary][google.cloud.dialogflow.v2.Conversations.SuggestConversationSummary]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{conversation=projects/*/conversations/*}/suggestions:suggestConversationSummary", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{conversation=projects/*/locations/*/conversations/*}/suggestions:suggestConversationSummary", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_suggest_conversation_summary( + request, metadata + ) + pb_request = gcd_conversation.SuggestConversationSummaryRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_conversation.SuggestConversationSummaryResponse() + pb_resp = gcd_conversation.SuggestConversationSummaryResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_suggest_conversation_summary(resp) + return resp + + @property + def complete_conversation( + self, + ) -> Callable[ + [conversation.CompleteConversationRequest], conversation.Conversation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CompleteConversation(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_conversation( + self, + ) -> Callable[ + [gcd_conversation.CreateConversationRequest], gcd_conversation.Conversation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateConversation(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_conversation( + self, + ) -> Callable[[conversation.GetConversationRequest], conversation.Conversation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetConversation(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_conversations( + self, + ) -> Callable[ + [conversation.ListConversationsRequest], conversation.ListConversationsResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListConversations(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_messages( + self, + ) -> Callable[ + [conversation.ListMessagesRequest], conversation.ListMessagesResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListMessages(self._session, self._host, self._interceptor) # type: ignore + + @property + def suggest_conversation_summary( + self, + ) -> Callable[ + [gcd_conversation.SuggestConversationSummaryRequest], + gcd_conversation.SuggestConversationSummaryResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SuggestConversationSummary(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ConversationsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ConversationsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ConversationsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ConversationsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ConversationsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ConversationsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/documents/client.py b/google/cloud/dialogflow_v2/services/documents/client.py index 9f6e8a1b9..73d7536aa 100644 --- a/google/cloud/dialogflow_v2/services/documents/client.py +++ b/google/cloud/dialogflow_v2/services/documents/client.py @@ -60,6 +60,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, DocumentsTransport from .transports.grpc import DocumentsGrpcTransport from .transports.grpc_asyncio import DocumentsGrpcAsyncIOTransport +from .transports.rest import DocumentsRestTransport class DocumentsClientMeta(type): @@ -73,6 +74,7 @@ class DocumentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[DocumentsTransport]] _transport_registry["grpc"] = DocumentsGrpcTransport _transport_registry["grpc_asyncio"] = DocumentsGrpcAsyncIOTransport + _transport_registry["rest"] = DocumentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/documents/transports/__init__.py b/google/cloud/dialogflow_v2/services/documents/transports/__init__.py index 5d938d116..d0736cf39 100644 --- a/google/cloud/dialogflow_v2/services/documents/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/documents/transports/__init__.py @@ -19,14 +19,18 @@ from .base import DocumentsTransport from .grpc import DocumentsGrpcTransport from .grpc_asyncio import DocumentsGrpcAsyncIOTransport +from .rest import DocumentsRestInterceptor, DocumentsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[DocumentsTransport]] _transport_registry["grpc"] = DocumentsGrpcTransport _transport_registry["grpc_asyncio"] = DocumentsGrpcAsyncIOTransport +_transport_registry["rest"] = DocumentsRestTransport __all__ = ( "DocumentsTransport", "DocumentsGrpcTransport", "DocumentsGrpcAsyncIOTransport", + "DocumentsRestTransport", + "DocumentsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/documents/transports/rest.py b/google/cloud/dialogflow_v2/services/documents/transports/rest.py new file mode 100644 index 000000000..3be0d4bc5 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/documents/transports/rest.py @@ -0,0 +1,1844 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import document +from google.cloud.dialogflow_v2.types import document as gcd_document + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import DocumentsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class DocumentsRestInterceptor: + """Interceptor for Documents. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the DocumentsRestTransport. + + .. code-block:: python + class MyCustomDocumentsInterceptor(DocumentsRestInterceptor): + def pre_create_document(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_document(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_document(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_delete_document(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_export_document(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_export_document(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_document(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_document(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_import_documents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_import_documents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_documents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_documents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_reload_document(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_reload_document(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_document(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_document(self, response): + logging.log(f"Received response: {response}") + return response + + transport = DocumentsRestTransport(interceptor=MyCustomDocumentsInterceptor()) + client = DocumentsClient(transport=transport) + + + """ + + def pre_create_document( + self, + request: gcd_document.CreateDocumentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_document.CreateDocumentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_document + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_create_document( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for create_document + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_delete_document( + self, + request: document.DeleteDocumentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[document.DeleteDocumentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_document + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_delete_document( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for delete_document + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_export_document( + self, + request: document.ExportDocumentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[document.ExportDocumentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for export_document + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_export_document( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for export_document + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_get_document( + self, request: document.GetDocumentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[document.GetDocumentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_document + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_get_document(self, response: document.Document) -> document.Document: + """Post-rpc interceptor for get_document + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_import_documents( + self, + request: document.ImportDocumentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[document.ImportDocumentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for import_documents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_import_documents( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for import_documents + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_list_documents( + self, + request: document.ListDocumentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[document.ListDocumentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_documents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_list_documents( + self, response: document.ListDocumentsResponse + ) -> document.ListDocumentsResponse: + """Post-rpc interceptor for list_documents + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_reload_document( + self, + request: document.ReloadDocumentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[document.ReloadDocumentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for reload_document + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_reload_document( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for reload_document + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_update_document( + self, + request: gcd_document.UpdateDocumentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_document.UpdateDocumentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_document + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_update_document( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for update_document + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class DocumentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: DocumentsRestInterceptor + + +class DocumentsRestTransport(DocumentsTransport): + """REST backend transport for Documents. + + Service for managing knowledge + [Documents][google.cloud.dialogflow.v2.Document]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[DocumentsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or DocumentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CreateDocument(DocumentsRestStub): + def __hash__(self): + return hash("CreateDocument") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_document.CreateDocumentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the create document method over HTTP. + + Args: + request (~.gcd_document.CreateDocumentRequest): + The request object. Request message for + [Documents.CreateDocument][google.cloud.dialogflow.v2.Documents.CreateDocument]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/knowledgeBases/*}/documents", + "body": "document", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/knowledgeBases/*}/documents", + "body": "document", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent/knowledgeBases/*}/documents", + "body": "document", + }, + ] + request, metadata = self._interceptor.pre_create_document(request, metadata) + pb_request = gcd_document.CreateDocumentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_document(resp) + return resp + + class _DeleteDocument(DocumentsRestStub): + def __hash__(self): + return hash("DeleteDocument") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: document.DeleteDocumentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the delete document method over HTTP. + + Args: + request (~.document.DeleteDocumentRequest): + The request object. Request message for + [Documents.DeleteDocument][google.cloud.dialogflow.v2.Documents.DeleteDocument]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/knowledgeBases/*/documents/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/knowledgeBases/*/documents/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/agent/knowledgeBases/*/documents/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_document(request, metadata) + pb_request = document.DeleteDocumentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_delete_document(resp) + return resp + + class _ExportDocument(DocumentsRestStub): + def __hash__(self): + return hash("ExportDocument") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: document.ExportDocumentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the export document method over HTTP. + + Args: + request (~.document.ExportDocumentRequest): + The request object. Request message for + [Documents.ExportDocument][google.cloud.dialogflow.v2.Documents.ExportDocument]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/knowledgeBases/*/documents/*}:export", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/knowledgeBases/*/documents/*}:export", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_export_document(request, metadata) + pb_request = document.ExportDocumentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_export_document(resp) + return resp + + class _GetDocument(DocumentsRestStub): + def __hash__(self): + return hash("GetDocument") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: document.GetDocumentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> document.Document: + r"""Call the get document method over HTTP. + + Args: + request (~.document.GetDocumentRequest): + The request object. Request message for + [Documents.GetDocument][google.cloud.dialogflow.v2.Documents.GetDocument]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.document.Document: + A knowledge document to be used by a + [KnowledgeBase][google.cloud.dialogflow.v2.KnowledgeBase]. + + For more information, see the `knowledge base + guide `__. + + Note: The ``projects.agent.knowledgeBases.documents`` + resource is deprecated; only use + ``projects.knowledgeBases.documents``. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/knowledgeBases/*/documents/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/knowledgeBases/*/documents/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/agent/knowledgeBases/*/documents/*}", + }, + ] + request, metadata = self._interceptor.pre_get_document(request, metadata) + pb_request = document.GetDocumentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = document.Document() + pb_resp = document.Document.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_document(resp) + return resp + + class _ImportDocuments(DocumentsRestStub): + def __hash__(self): + return hash("ImportDocuments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: document.ImportDocumentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the import documents method over HTTP. + + Args: + request (~.document.ImportDocumentsRequest): + The request object. Request message for + [Documents.ImportDocuments][google.cloud.dialogflow.v2.Documents.ImportDocuments]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/knowledgeBases/*}/documents:import", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/knowledgeBases/*}/documents:import", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_import_documents( + request, metadata + ) + pb_request = document.ImportDocumentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_import_documents(resp) + return resp + + class _ListDocuments(DocumentsRestStub): + def __hash__(self): + return hash("ListDocuments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: document.ListDocumentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> document.ListDocumentsResponse: + r"""Call the list documents method over HTTP. + + Args: + request (~.document.ListDocumentsRequest): + The request object. Request message for + [Documents.ListDocuments][google.cloud.dialogflow.v2.Documents.ListDocuments]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.document.ListDocumentsResponse: + Response message for + [Documents.ListDocuments][google.cloud.dialogflow.v2.Documents.ListDocuments]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/knowledgeBases/*}/documents", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/knowledgeBases/*}/documents", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent/knowledgeBases/*}/documents", + }, + ] + request, metadata = self._interceptor.pre_list_documents(request, metadata) + pb_request = document.ListDocumentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = document.ListDocumentsResponse() + pb_resp = document.ListDocumentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_documents(resp) + return resp + + class _ReloadDocument(DocumentsRestStub): + def __hash__(self): + return hash("ReloadDocument") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: document.ReloadDocumentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the reload document method over HTTP. + + Args: + request (~.document.ReloadDocumentRequest): + The request object. Request message for + [Documents.ReloadDocument][google.cloud.dialogflow.v2.Documents.ReloadDocument]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/knowledgeBases/*/documents/*}:reload", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/knowledgeBases/*/documents/*}:reload", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/agent/knowledgeBases/*/documents/*}:reload", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_reload_document(request, metadata) + pb_request = document.ReloadDocumentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_reload_document(resp) + return resp + + class _UpdateDocument(DocumentsRestStub): + def __hash__(self): + return hash("UpdateDocument") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_document.UpdateDocumentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the update document method over HTTP. + + Args: + request (~.gcd_document.UpdateDocumentRequest): + The request object. Request message for + [Documents.UpdateDocument][google.cloud.dialogflow.v2.Documents.UpdateDocument]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{document.name=projects/*/knowledgeBases/*/documents/*}", + "body": "document", + }, + { + "method": "patch", + "uri": "/v2/{document.name=projects/*/locations/*/knowledgeBases/*/documents/*}", + "body": "document", + }, + { + "method": "patch", + "uri": "/v2/{document.name=projects/*/agent/knowledgeBases/*/documents/*}", + "body": "document", + }, + ] + request, metadata = self._interceptor.pre_update_document(request, metadata) + pb_request = gcd_document.UpdateDocumentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_document(resp) + return resp + + @property + def create_document( + self, + ) -> Callable[[gcd_document.CreateDocumentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateDocument(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_document( + self, + ) -> Callable[[document.DeleteDocumentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteDocument(self._session, self._host, self._interceptor) # type: ignore + + @property + def export_document( + self, + ) -> Callable[[document.ExportDocumentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ExportDocument(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_document( + self, + ) -> Callable[[document.GetDocumentRequest], document.Document]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetDocument(self._session, self._host, self._interceptor) # type: ignore + + @property + def import_documents( + self, + ) -> Callable[[document.ImportDocumentsRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ImportDocuments(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_documents( + self, + ) -> Callable[[document.ListDocumentsRequest], document.ListDocumentsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListDocuments(self._session, self._host, self._interceptor) # type: ignore + + @property + def reload_document( + self, + ) -> Callable[[document.ReloadDocumentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ReloadDocument(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_document( + self, + ) -> Callable[[gcd_document.UpdateDocumentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateDocument(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(DocumentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(DocumentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(DocumentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(DocumentsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(DocumentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("DocumentsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/entity_types/client.py b/google/cloud/dialogflow_v2/services/entity_types/client.py index 79dd9ed19..208cc64e8 100644 --- a/google/cloud/dialogflow_v2/services/entity_types/client.py +++ b/google/cloud/dialogflow_v2/services/entity_types/client.py @@ -60,6 +60,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, EntityTypesTransport from .transports.grpc import EntityTypesGrpcTransport from .transports.grpc_asyncio import EntityTypesGrpcAsyncIOTransport +from .transports.rest import EntityTypesRestTransport class EntityTypesClientMeta(type): @@ -73,6 +74,7 @@ class EntityTypesClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[EntityTypesTransport]] _transport_registry["grpc"] = EntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = EntityTypesGrpcAsyncIOTransport + _transport_registry["rest"] = EntityTypesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/entity_types/transports/__init__.py b/google/cloud/dialogflow_v2/services/entity_types/transports/__init__.py index 68efe567e..c60b49aa5 100644 --- a/google/cloud/dialogflow_v2/services/entity_types/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/entity_types/transports/__init__.py @@ -19,14 +19,18 @@ from .base import EntityTypesTransport from .grpc import EntityTypesGrpcTransport from .grpc_asyncio import EntityTypesGrpcAsyncIOTransport +from .rest import EntityTypesRestInterceptor, EntityTypesRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[EntityTypesTransport]] _transport_registry["grpc"] = EntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = EntityTypesGrpcAsyncIOTransport +_transport_registry["rest"] = EntityTypesRestTransport __all__ = ( "EntityTypesTransport", "EntityTypesGrpcTransport", "EntityTypesGrpcAsyncIOTransport", + "EntityTypesRestTransport", + "EntityTypesRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/entity_types/transports/rest.py b/google/cloud/dialogflow_v2/services/entity_types/transports/rest.py new file mode 100644 index 000000000..37d006938 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/entity_types/transports/rest.py @@ -0,0 +1,2138 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import entity_type +from google.cloud.dialogflow_v2.types import entity_type as gcd_entity_type + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import EntityTypesTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class EntityTypesRestInterceptor: + """Interceptor for EntityTypes. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the EntityTypesRestTransport. + + .. code-block:: python + class MyCustomEntityTypesInterceptor(EntityTypesRestInterceptor): + def pre_batch_create_entities(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_create_entities(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_delete_entities(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_delete_entities(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_delete_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_delete_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_update_entities(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_update_entities(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_update_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_update_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + transport = EntityTypesRestTransport(interceptor=MyCustomEntityTypesInterceptor()) + client = EntityTypesClient(transport=transport) + + + """ + + def pre_batch_create_entities( + self, + request: entity_type.BatchCreateEntitiesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.BatchCreateEntitiesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_create_entities + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_batch_create_entities( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_create_entities + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_batch_delete_entities( + self, + request: entity_type.BatchDeleteEntitiesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.BatchDeleteEntitiesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_delete_entities + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_batch_delete_entities( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_delete_entities + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_batch_delete_entity_types( + self, + request: entity_type.BatchDeleteEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.BatchDeleteEntityTypesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_delete_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_batch_delete_entity_types( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_delete_entity_types + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_batch_update_entities( + self, + request: entity_type.BatchUpdateEntitiesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.BatchUpdateEntitiesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_update_entities + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_batch_update_entities( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_update_entities + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_batch_update_entity_types( + self, + request: entity_type.BatchUpdateEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.BatchUpdateEntityTypesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_update_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_batch_update_entity_types( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_update_entity_types + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_create_entity_type( + self, + request: gcd_entity_type.CreateEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_entity_type.CreateEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_create_entity_type( + self, response: gcd_entity_type.EntityType + ) -> gcd_entity_type.EntityType: + """Post-rpc interceptor for create_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_delete_entity_type( + self, + request: entity_type.DeleteEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.DeleteEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def pre_get_entity_type( + self, + request: entity_type.GetEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.GetEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_entity_type( + self, response: entity_type.EntityType + ) -> entity_type.EntityType: + """Post-rpc interceptor for get_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_entity_types( + self, + request: entity_type.ListEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.ListEntityTypesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_entity_types( + self, response: entity_type.ListEntityTypesResponse + ) -> entity_type.ListEntityTypesResponse: + """Post-rpc interceptor for list_entity_types + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_update_entity_type( + self, + request: gcd_entity_type.UpdateEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_entity_type.UpdateEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_update_entity_type( + self, response: gcd_entity_type.EntityType + ) -> gcd_entity_type.EntityType: + """Post-rpc interceptor for update_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class EntityTypesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: EntityTypesRestInterceptor + + +class EntityTypesRestTransport(EntityTypesTransport): + """REST backend transport for EntityTypes. + + Service for managing + [EntityTypes][google.cloud.dialogflow.v2.EntityType]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[EntityTypesRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or EntityTypesRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _BatchCreateEntities(EntityTypesRestStub): + def __hash__(self): + return hash("BatchCreateEntities") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.BatchCreateEntitiesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch create entities method over HTTP. + + Args: + request (~.entity_type.BatchCreateEntitiesRequest): + The request object. The request message for + [EntityTypes.BatchCreateEntities][google.cloud.dialogflow.v2.EntityTypes.BatchCreateEntities]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent/entityTypes/*}/entities:batchCreate", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent/entityTypes/*}/entities:batchCreate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_create_entities( + request, metadata + ) + pb_request = entity_type.BatchCreateEntitiesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_create_entities(resp) + return resp + + class _BatchDeleteEntities(EntityTypesRestStub): + def __hash__(self): + return hash("BatchDeleteEntities") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.BatchDeleteEntitiesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch delete entities method over HTTP. + + Args: + request (~.entity_type.BatchDeleteEntitiesRequest): + The request object. The request message for + [EntityTypes.BatchDeleteEntities][google.cloud.dialogflow.v2.EntityTypes.BatchDeleteEntities]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent/entityTypes/*}/entities:batchDelete", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent/entityTypes/*}/entities:batchDelete", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_delete_entities( + request, metadata + ) + pb_request = entity_type.BatchDeleteEntitiesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_delete_entities(resp) + return resp + + class _BatchDeleteEntityTypes(EntityTypesRestStub): + def __hash__(self): + return hash("BatchDeleteEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.BatchDeleteEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch delete entity types method over HTTP. + + Args: + request (~.entity_type.BatchDeleteEntityTypesRequest): + The request object. The request message for + [EntityTypes.BatchDeleteEntityTypes][google.cloud.dialogflow.v2.EntityTypes.BatchDeleteEntityTypes]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent}/entityTypes:batchDelete", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent}/entityTypes:batchDelete", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_delete_entity_types( + request, metadata + ) + pb_request = entity_type.BatchDeleteEntityTypesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_delete_entity_types(resp) + return resp + + class _BatchUpdateEntities(EntityTypesRestStub): + def __hash__(self): + return hash("BatchUpdateEntities") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.BatchUpdateEntitiesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch update entities method over HTTP. + + Args: + request (~.entity_type.BatchUpdateEntitiesRequest): + The request object. The request message for + [EntityTypes.BatchUpdateEntities][google.cloud.dialogflow.v2.EntityTypes.BatchUpdateEntities]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent/entityTypes/*}/entities:batchUpdate", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent/entityTypes/*}/entities:batchUpdate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_update_entities( + request, metadata + ) + pb_request = entity_type.BatchUpdateEntitiesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_update_entities(resp) + return resp + + class _BatchUpdateEntityTypes(EntityTypesRestStub): + def __hash__(self): + return hash("BatchUpdateEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.BatchUpdateEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch update entity types method over HTTP. + + Args: + request (~.entity_type.BatchUpdateEntityTypesRequest): + The request object. The request message for + [EntityTypes.BatchUpdateEntityTypes][google.cloud.dialogflow.v2.EntityTypes.BatchUpdateEntityTypes]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent}/entityTypes:batchUpdate", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent}/entityTypes:batchUpdate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_update_entity_types( + request, metadata + ) + pb_request = entity_type.BatchUpdateEntityTypesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_update_entity_types(resp) + return resp + + class _CreateEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("CreateEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_entity_type.CreateEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_entity_type.EntityType: + r"""Call the create entity type method over HTTP. + + Args: + request (~.gcd_entity_type.CreateEntityTypeRequest): + The request object. The request message for + [EntityTypes.CreateEntityType][google.cloud.dialogflow.v2.EntityTypes.CreateEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_entity_type.EntityType: + Each intent parameter has a type, called the entity + type, which dictates exactly how data from an end-user + expression is extracted. + + Dialogflow provides predefined system entities that can + match many common types of data. For example, there are + system entities for matching dates, times, colors, email + addresses, and so on. You can also create your own + custom entities for matching custom data. For example, + you could define a vegetable entity that can match the + types of vegetables available for purchase with a + grocery store agent. + + For more information, see the `Entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent}/entityTypes", + "body": "entity_type", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent}/entityTypes", + "body": "entity_type", + }, + ] + request, metadata = self._interceptor.pre_create_entity_type( + request, metadata + ) + pb_request = gcd_entity_type.CreateEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_entity_type.EntityType() + pb_resp = gcd_entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_entity_type(resp) + return resp + + class _DeleteEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("DeleteEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.DeleteEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete entity type method over HTTP. + + Args: + request (~.entity_type.DeleteEntityTypeRequest): + The request object. The request message for + [EntityTypes.DeleteEntityType][google.cloud.dialogflow.v2.EntityTypes.DeleteEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/agent/entityTypes/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/agent/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_entity_type( + request, metadata + ) + pb_request = entity_type.DeleteEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("GetEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.GetEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> entity_type.EntityType: + r"""Call the get entity type method over HTTP. + + Args: + request (~.entity_type.GetEntityTypeRequest): + The request object. The request message for + [EntityTypes.GetEntityType][google.cloud.dialogflow.v2.EntityTypes.GetEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.entity_type.EntityType: + Each intent parameter has a type, called the entity + type, which dictates exactly how data from an end-user + expression is extracted. + + Dialogflow provides predefined system entities that can + match many common types of data. For example, there are + system entities for matching dates, times, colors, email + addresses, and so on. You can also create your own + custom entities for matching custom data. For example, + you could define a vegetable entity that can match the + types of vegetables available for purchase with a + grocery store agent. + + For more information, see the `Entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/agent/entityTypes/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/agent/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_get_entity_type(request, metadata) + pb_request = entity_type.GetEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = entity_type.EntityType() + pb_resp = entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_entity_type(resp) + return resp + + class _ListEntityTypes(EntityTypesRestStub): + def __hash__(self): + return hash("ListEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.ListEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> entity_type.ListEntityTypesResponse: + r"""Call the list entity types method over HTTP. + + Args: + request (~.entity_type.ListEntityTypesRequest): + The request object. The request message for + [EntityTypes.ListEntityTypes][google.cloud.dialogflow.v2.EntityTypes.ListEntityTypes]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.entity_type.ListEntityTypesResponse: + The response message for + [EntityTypes.ListEntityTypes][google.cloud.dialogflow.v2.EntityTypes.ListEntityTypes]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent}/entityTypes", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/agent}/entityTypes", + }, + ] + request, metadata = self._interceptor.pre_list_entity_types( + request, metadata + ) + pb_request = entity_type.ListEntityTypesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = entity_type.ListEntityTypesResponse() + pb_resp = entity_type.ListEntityTypesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_entity_types(resp) + return resp + + class _UpdateEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("UpdateEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_entity_type.UpdateEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_entity_type.EntityType: + r"""Call the update entity type method over HTTP. + + Args: + request (~.gcd_entity_type.UpdateEntityTypeRequest): + The request object. The request message for + [EntityTypes.UpdateEntityType][google.cloud.dialogflow.v2.EntityTypes.UpdateEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_entity_type.EntityType: + Each intent parameter has a type, called the entity + type, which dictates exactly how data from an end-user + expression is extracted. + + Dialogflow provides predefined system entities that can + match many common types of data. For example, there are + system entities for matching dates, times, colors, email + addresses, and so on. You can also create your own + custom entities for matching custom data. For example, + you could define a vegetable entity that can match the + types of vegetables available for purchase with a + grocery store agent. + + For more information, see the `Entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{entity_type.name=projects/*/agent/entityTypes/*}", + "body": "entity_type", + }, + { + "method": "patch", + "uri": "/v2/{entity_type.name=projects/*/locations/*/agent/entityTypes/*}", + "body": "entity_type", + }, + ] + request, metadata = self._interceptor.pre_update_entity_type( + request, metadata + ) + pb_request = gcd_entity_type.UpdateEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_entity_type.EntityType() + pb_resp = gcd_entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_entity_type(resp) + return resp + + @property + def batch_create_entities( + self, + ) -> Callable[[entity_type.BatchCreateEntitiesRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchCreateEntities(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_delete_entities( + self, + ) -> Callable[[entity_type.BatchDeleteEntitiesRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchDeleteEntities(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_delete_entity_types( + self, + ) -> Callable[ + [entity_type.BatchDeleteEntityTypesRequest], operations_pb2.Operation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchDeleteEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_update_entities( + self, + ) -> Callable[[entity_type.BatchUpdateEntitiesRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchUpdateEntities(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_update_entity_types( + self, + ) -> Callable[ + [entity_type.BatchUpdateEntityTypesRequest], operations_pb2.Operation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchUpdateEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_entity_type( + self, + ) -> Callable[ + [gcd_entity_type.CreateEntityTypeRequest], gcd_entity_type.EntityType + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_entity_type( + self, + ) -> Callable[[entity_type.DeleteEntityTypeRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_entity_type( + self, + ) -> Callable[[entity_type.GetEntityTypeRequest], entity_type.EntityType]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_entity_types( + self, + ) -> Callable[ + [entity_type.ListEntityTypesRequest], entity_type.ListEntityTypesResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_entity_type( + self, + ) -> Callable[ + [gcd_entity_type.UpdateEntityTypeRequest], gcd_entity_type.EntityType + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(EntityTypesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(EntityTypesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(EntityTypesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(EntityTypesRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(EntityTypesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("EntityTypesRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/environments/client.py b/google/cloud/dialogflow_v2/services/environments/client.py index 602be93f6..4db61eb37 100644 --- a/google/cloud/dialogflow_v2/services/environments/client.py +++ b/google/cloud/dialogflow_v2/services/environments/client.py @@ -56,6 +56,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, EnvironmentsTransport from .transports.grpc import EnvironmentsGrpcTransport from .transports.grpc_asyncio import EnvironmentsGrpcAsyncIOTransport +from .transports.rest import EnvironmentsRestTransport class EnvironmentsClientMeta(type): @@ -69,6 +70,7 @@ class EnvironmentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[EnvironmentsTransport]] _transport_registry["grpc"] = EnvironmentsGrpcTransport _transport_registry["grpc_asyncio"] = EnvironmentsGrpcAsyncIOTransport + _transport_registry["rest"] = EnvironmentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/environments/transports/__init__.py b/google/cloud/dialogflow_v2/services/environments/transports/__init__.py index abc173bb4..f8e2a8257 100644 --- a/google/cloud/dialogflow_v2/services/environments/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/environments/transports/__init__.py @@ -19,14 +19,18 @@ from .base import EnvironmentsTransport from .grpc import EnvironmentsGrpcTransport from .grpc_asyncio import EnvironmentsGrpcAsyncIOTransport +from .rest import EnvironmentsRestInterceptor, EnvironmentsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[EnvironmentsTransport]] _transport_registry["grpc"] = EnvironmentsGrpcTransport _transport_registry["grpc_asyncio"] = EnvironmentsGrpcAsyncIOTransport +_transport_registry["rest"] = EnvironmentsRestTransport __all__ = ( "EnvironmentsTransport", "EnvironmentsGrpcTransport", "EnvironmentsGrpcAsyncIOTransport", + "EnvironmentsRestTransport", + "EnvironmentsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/environments/transports/rest.py b/google/cloud/dialogflow_v2/services/environments/transports/rest.py new file mode 100644 index 000000000..05dba86e4 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/environments/transports/rest.py @@ -0,0 +1,1496 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import environment + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import EnvironmentsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class EnvironmentsRestInterceptor: + """Interceptor for Environments. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the EnvironmentsRestTransport. + + .. code-block:: python + class MyCustomEnvironmentsInterceptor(EnvironmentsRestInterceptor): + def pre_create_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_environment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_environment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_environment_history(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_environment_history(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_environments(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_environments(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_environment(self, response): + logging.log(f"Received response: {response}") + return response + + transport = EnvironmentsRestTransport(interceptor=MyCustomEnvironmentsInterceptor()) + client = EnvironmentsClient(transport=transport) + + + """ + + def pre_create_environment( + self, + request: environment.CreateEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.CreateEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_create_environment( + self, response: environment.Environment + ) -> environment.Environment: + """Post-rpc interceptor for create_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_delete_environment( + self, + request: environment.DeleteEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.DeleteEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def pre_get_environment( + self, + request: environment.GetEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.GetEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_environment( + self, response: environment.Environment + ) -> environment.Environment: + """Post-rpc interceptor for get_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_get_environment_history( + self, + request: environment.GetEnvironmentHistoryRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.GetEnvironmentHistoryRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_environment_history + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_environment_history( + self, response: environment.EnvironmentHistory + ) -> environment.EnvironmentHistory: + """Post-rpc interceptor for get_environment_history + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_environments( + self, + request: environment.ListEnvironmentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.ListEnvironmentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_environments + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_environments( + self, response: environment.ListEnvironmentsResponse + ) -> environment.ListEnvironmentsResponse: + """Post-rpc interceptor for list_environments + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_update_environment( + self, + request: environment.UpdateEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.UpdateEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_update_environment( + self, response: environment.Environment + ) -> environment.Environment: + """Post-rpc interceptor for update_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class EnvironmentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: EnvironmentsRestInterceptor + + +class EnvironmentsRestTransport(EnvironmentsTransport): + """REST backend transport for Environments. + + Service for managing + [Environments][google.cloud.dialogflow.v2.Environment]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[EnvironmentsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or EnvironmentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("CreateEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "environmentId": "", + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.CreateEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.Environment: + r"""Call the create environment method over HTTP. + + Args: + request (~.environment.CreateEnvironmentRequest): + The request object. The request message for + [Environments.CreateEnvironment][google.cloud.dialogflow.v2.Environments.CreateEnvironment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.environment.Environment: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent}/environments", + "body": "environment", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent}/environments", + "body": "environment", + }, + ] + request, metadata = self._interceptor.pre_create_environment( + request, metadata + ) + pb_request = environment.CreateEnvironmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = environment.Environment() + pb_resp = environment.Environment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_environment(resp) + return resp + + class _DeleteEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("DeleteEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.DeleteEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete environment method over HTTP. + + Args: + request (~.environment.DeleteEnvironmentRequest): + The request object. The request message for + [Environments.DeleteEnvironment][google.cloud.dialogflow.v2.Environments.DeleteEnvironment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/agent/environments/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/agent/environments/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_environment( + request, metadata + ) + pb_request = environment.DeleteEnvironmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("GetEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.GetEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.Environment: + r"""Call the get environment method over HTTP. + + Args: + request (~.environment.GetEnvironmentRequest): + The request object. The request message for + [Environments.GetEnvironment][google.cloud.dialogflow.v2.Environments.GetEnvironment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.environment.Environment: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/agent/environments/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/agent/environments/*}", + }, + ] + request, metadata = self._interceptor.pre_get_environment(request, metadata) + pb_request = environment.GetEnvironmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = environment.Environment() + pb_resp = environment.Environment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_environment(resp) + return resp + + class _GetEnvironmentHistory(EnvironmentsRestStub): + def __hash__(self): + return hash("GetEnvironmentHistory") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.GetEnvironmentHistoryRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.EnvironmentHistory: + r"""Call the get environment history method over HTTP. + + Args: + request (~.environment.GetEnvironmentHistoryRequest): + The request object. The request message for + [Environments.GetEnvironmentHistory][google.cloud.dialogflow.v2.Environments.GetEnvironmentHistory]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.environment.EnvironmentHistory: + The response message for + [Environments.GetEnvironmentHistory][google.cloud.dialogflow.v2.Environments.GetEnvironmentHistory]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent/environments/*}/history", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/agent/environments/*}/history", + }, + ] + request, metadata = self._interceptor.pre_get_environment_history( + request, metadata + ) + pb_request = environment.GetEnvironmentHistoryRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = environment.EnvironmentHistory() + pb_resp = environment.EnvironmentHistory.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_environment_history(resp) + return resp + + class _ListEnvironments(EnvironmentsRestStub): + def __hash__(self): + return hash("ListEnvironments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.ListEnvironmentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.ListEnvironmentsResponse: + r"""Call the list environments method over HTTP. + + Args: + request (~.environment.ListEnvironmentsRequest): + The request object. The request message for + [Environments.ListEnvironments][google.cloud.dialogflow.v2.Environments.ListEnvironments]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.environment.ListEnvironmentsResponse: + The response message for + [Environments.ListEnvironments][google.cloud.dialogflow.v2.Environments.ListEnvironments]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent}/environments", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/agent}/environments", + }, + ] + request, metadata = self._interceptor.pre_list_environments( + request, metadata + ) + pb_request = environment.ListEnvironmentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = environment.ListEnvironmentsResponse() + pb_resp = environment.ListEnvironmentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_environments(resp) + return resp + + class _UpdateEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("UpdateEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.UpdateEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.Environment: + r"""Call the update environment method over HTTP. + + Args: + request (~.environment.UpdateEnvironmentRequest): + The request object. The request message for + [Environments.UpdateEnvironment][google.cloud.dialogflow.v2.Environments.UpdateEnvironment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.environment.Environment: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{environment.name=projects/*/agent/environments/*}", + "body": "environment", + }, + { + "method": "patch", + "uri": "/v2/{environment.name=projects/*/locations/*/agent/environments/*}", + "body": "environment", + }, + ] + request, metadata = self._interceptor.pre_update_environment( + request, metadata + ) + pb_request = environment.UpdateEnvironmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = environment.Environment() + pb_resp = environment.Environment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_environment(resp) + return resp + + @property + def create_environment( + self, + ) -> Callable[[environment.CreateEnvironmentRequest], environment.Environment]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_environment( + self, + ) -> Callable[[environment.DeleteEnvironmentRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_environment( + self, + ) -> Callable[[environment.GetEnvironmentRequest], environment.Environment]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_environment_history( + self, + ) -> Callable[ + [environment.GetEnvironmentHistoryRequest], environment.EnvironmentHistory + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetEnvironmentHistory(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_environments( + self, + ) -> Callable[ + [environment.ListEnvironmentsRequest], environment.ListEnvironmentsResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListEnvironments(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_environment( + self, + ) -> Callable[[environment.UpdateEnvironmentRequest], environment.Environment]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(EnvironmentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(EnvironmentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(EnvironmentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(EnvironmentsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(EnvironmentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("EnvironmentsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/fulfillments/client.py b/google/cloud/dialogflow_v2/services/fulfillments/client.py index 06663489f..fced9a887 100644 --- a/google/cloud/dialogflow_v2/services/fulfillments/client.py +++ b/google/cloud/dialogflow_v2/services/fulfillments/client.py @@ -56,6 +56,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, FulfillmentsTransport from .transports.grpc import FulfillmentsGrpcTransport from .transports.grpc_asyncio import FulfillmentsGrpcAsyncIOTransport +from .transports.rest import FulfillmentsRestTransport class FulfillmentsClientMeta(type): @@ -69,6 +70,7 @@ class FulfillmentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[FulfillmentsTransport]] _transport_registry["grpc"] = FulfillmentsGrpcTransport _transport_registry["grpc_asyncio"] = FulfillmentsGrpcAsyncIOTransport + _transport_registry["rest"] = FulfillmentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/fulfillments/transports/__init__.py b/google/cloud/dialogflow_v2/services/fulfillments/transports/__init__.py index e3a19cdc3..b2f6ffd50 100644 --- a/google/cloud/dialogflow_v2/services/fulfillments/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/fulfillments/transports/__init__.py @@ -19,14 +19,18 @@ from .base import FulfillmentsTransport from .grpc import FulfillmentsGrpcTransport from .grpc_asyncio import FulfillmentsGrpcAsyncIOTransport +from .rest import FulfillmentsRestInterceptor, FulfillmentsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[FulfillmentsTransport]] _transport_registry["grpc"] = FulfillmentsGrpcTransport _transport_registry["grpc_asyncio"] = FulfillmentsGrpcAsyncIOTransport +_transport_registry["rest"] = FulfillmentsRestTransport __all__ = ( "FulfillmentsTransport", "FulfillmentsGrpcTransport", "FulfillmentsGrpcAsyncIOTransport", + "FulfillmentsRestTransport", + "FulfillmentsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/fulfillments/transports/rest.py b/google/cloud/dialogflow_v2/services/fulfillments/transports/rest.py new file mode 100644 index 000000000..ad5f4e2d6 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/fulfillments/transports/rest.py @@ -0,0 +1,939 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.dialogflow_v2.types import fulfillment +from google.cloud.dialogflow_v2.types import fulfillment as gcd_fulfillment + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import FulfillmentsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class FulfillmentsRestInterceptor: + """Interceptor for Fulfillments. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the FulfillmentsRestTransport. + + .. code-block:: python + class MyCustomFulfillmentsInterceptor(FulfillmentsRestInterceptor): + def pre_get_fulfillment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_fulfillment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_fulfillment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_fulfillment(self, response): + logging.log(f"Received response: {response}") + return response + + transport = FulfillmentsRestTransport(interceptor=MyCustomFulfillmentsInterceptor()) + client = FulfillmentsClient(transport=transport) + + + """ + + def pre_get_fulfillment( + self, + request: fulfillment.GetFulfillmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[fulfillment.GetFulfillmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_fulfillment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_get_fulfillment( + self, response: fulfillment.Fulfillment + ) -> fulfillment.Fulfillment: + """Post-rpc interceptor for get_fulfillment + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_update_fulfillment( + self, + request: gcd_fulfillment.UpdateFulfillmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_fulfillment.UpdateFulfillmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_fulfillment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_update_fulfillment( + self, response: gcd_fulfillment.Fulfillment + ) -> gcd_fulfillment.Fulfillment: + """Post-rpc interceptor for update_fulfillment + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class FulfillmentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: FulfillmentsRestInterceptor + + +class FulfillmentsRestTransport(FulfillmentsTransport): + """REST backend transport for Fulfillments. + + Service for managing + [Fulfillments][google.cloud.dialogflow.v2.Fulfillment]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[FulfillmentsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or FulfillmentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _GetFulfillment(FulfillmentsRestStub): + def __hash__(self): + return hash("GetFulfillment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: fulfillment.GetFulfillmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> fulfillment.Fulfillment: + r"""Call the get fulfillment method over HTTP. + + Args: + request (~.fulfillment.GetFulfillmentRequest): + The request object. The request message for + [Fulfillments.GetFulfillment][google.cloud.dialogflow.v2.Fulfillments.GetFulfillment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.fulfillment.Fulfillment: + By default, your agent responds to a matched intent with + a static response. As an alternative, you can provide a + more dynamic response by using fulfillment. When you + enable fulfillment for an intent, Dialogflow responds to + that intent by calling a service that you define. For + example, if an end-user wants to schedule a haircut on + Friday, your service can check your database and respond + to the end-user with availability information for + Friday. + + For more information, see the `fulfillment + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/agent/fulfillment}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/agent/fulfillment}", + }, + ] + request, metadata = self._interceptor.pre_get_fulfillment(request, metadata) + pb_request = fulfillment.GetFulfillmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = fulfillment.Fulfillment() + pb_resp = fulfillment.Fulfillment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_fulfillment(resp) + return resp + + class _UpdateFulfillment(FulfillmentsRestStub): + def __hash__(self): + return hash("UpdateFulfillment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_fulfillment.UpdateFulfillmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_fulfillment.Fulfillment: + r"""Call the update fulfillment method over HTTP. + + Args: + request (~.gcd_fulfillment.UpdateFulfillmentRequest): + The request object. The request message for + [Fulfillments.UpdateFulfillment][google.cloud.dialogflow.v2.Fulfillments.UpdateFulfillment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_fulfillment.Fulfillment: + By default, your agent responds to a matched intent with + a static response. As an alternative, you can provide a + more dynamic response by using fulfillment. When you + enable fulfillment for an intent, Dialogflow responds to + that intent by calling a service that you define. For + example, if an end-user wants to schedule a haircut on + Friday, your service can check your database and respond + to the end-user with availability information for + Friday. + + For more information, see the `fulfillment + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{fulfillment.name=projects/*/agent/fulfillment}", + "body": "fulfillment", + }, + { + "method": "patch", + "uri": "/v2/{fulfillment.name=projects/*/locations/*/agent/fulfillment}", + "body": "fulfillment", + }, + ] + request, metadata = self._interceptor.pre_update_fulfillment( + request, metadata + ) + pb_request = gcd_fulfillment.UpdateFulfillmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_fulfillment.Fulfillment() + pb_resp = gcd_fulfillment.Fulfillment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_fulfillment(resp) + return resp + + @property + def get_fulfillment( + self, + ) -> Callable[[fulfillment.GetFulfillmentRequest], fulfillment.Fulfillment]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetFulfillment(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_fulfillment( + self, + ) -> Callable[ + [gcd_fulfillment.UpdateFulfillmentRequest], gcd_fulfillment.Fulfillment + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateFulfillment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(FulfillmentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(FulfillmentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(FulfillmentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(FulfillmentsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(FulfillmentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("FulfillmentsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/intents/client.py b/google/cloud/dialogflow_v2/services/intents/client.py index d7138d3ac..c7ce11e04 100644 --- a/google/cloud/dialogflow_v2/services/intents/client.py +++ b/google/cloud/dialogflow_v2/services/intents/client.py @@ -62,6 +62,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, IntentsTransport from .transports.grpc import IntentsGrpcTransport from .transports.grpc_asyncio import IntentsGrpcAsyncIOTransport +from .transports.rest import IntentsRestTransport class IntentsClientMeta(type): @@ -75,6 +76,7 @@ class IntentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[IntentsTransport]] _transport_registry["grpc"] = IntentsGrpcTransport _transport_registry["grpc_asyncio"] = IntentsGrpcAsyncIOTransport + _transport_registry["rest"] = IntentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/intents/transports/__init__.py b/google/cloud/dialogflow_v2/services/intents/transports/__init__.py index a325bcd97..794b2f132 100644 --- a/google/cloud/dialogflow_v2/services/intents/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/intents/transports/__init__.py @@ -19,14 +19,18 @@ from .base import IntentsTransport from .grpc import IntentsGrpcTransport from .grpc_asyncio import IntentsGrpcAsyncIOTransport +from .rest import IntentsRestInterceptor, IntentsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[IntentsTransport]] _transport_registry["grpc"] = IntentsGrpcTransport _transport_registry["grpc_asyncio"] = IntentsGrpcAsyncIOTransport +_transport_registry["rest"] = IntentsRestTransport __all__ = ( "IntentsTransport", "IntentsGrpcTransport", "IntentsGrpcAsyncIOTransport", + "IntentsRestTransport", + "IntentsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/intents/transports/rest.py b/google/cloud/dialogflow_v2/services/intents/transports/rest.py new file mode 100644 index 000000000..1a090149f --- /dev/null +++ b/google/cloud/dialogflow_v2/services/intents/transports/rest.py @@ -0,0 +1,1665 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import intent +from google.cloud.dialogflow_v2.types import intent as gcd_intent + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import IntentsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class IntentsRestInterceptor: + """Interceptor for Intents. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the IntentsRestTransport. + + .. code-block:: python + class MyCustomIntentsInterceptor(IntentsRestInterceptor): + def pre_batch_delete_intents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_delete_intents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_update_intents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_update_intents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_intents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_intents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_intent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = IntentsRestTransport(interceptor=MyCustomIntentsInterceptor()) + client = IntentsClient(transport=transport) + + + """ + + def pre_batch_delete_intents( + self, + request: intent.BatchDeleteIntentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[intent.BatchDeleteIntentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_delete_intents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_batch_delete_intents( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_delete_intents + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_batch_update_intents( + self, + request: intent.BatchUpdateIntentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[intent.BatchUpdateIntentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_update_intents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_batch_update_intents( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_update_intents + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_create_intent( + self, + request: gcd_intent.CreateIntentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_intent.CreateIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_create_intent(self, response: gcd_intent.Intent) -> gcd_intent.Intent: + """Post-rpc interceptor for create_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_delete_intent( + self, request: intent.DeleteIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.DeleteIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def pre_get_intent( + self, request: intent.GetIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.GetIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_intent(self, response: intent.Intent) -> intent.Intent: + """Post-rpc interceptor for get_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_intents( + self, request: intent.ListIntentsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.ListIntentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_intents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_intents( + self, response: intent.ListIntentsResponse + ) -> intent.ListIntentsResponse: + """Post-rpc interceptor for list_intents + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_update_intent( + self, + request: gcd_intent.UpdateIntentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_intent.UpdateIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_update_intent(self, response: gcd_intent.Intent) -> gcd_intent.Intent: + """Post-rpc interceptor for update_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class IntentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: IntentsRestInterceptor + + +class IntentsRestTransport(IntentsTransport): + """REST backend transport for Intents. + + Service for managing [Intents][google.cloud.dialogflow.v2.Intent]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[IntentsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or IntentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _BatchDeleteIntents(IntentsRestStub): + def __hash__(self): + return hash("BatchDeleteIntents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: intent.BatchDeleteIntentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch delete intents method over HTTP. + + Args: + request (~.intent.BatchDeleteIntentsRequest): + The request object. The request message for + [Intents.BatchDeleteIntents][google.cloud.dialogflow.v2.Intents.BatchDeleteIntents]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent}/intents:batchDelete", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent}/intents:batchDelete", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_delete_intents( + request, metadata + ) + pb_request = intent.BatchDeleteIntentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_delete_intents(resp) + return resp + + class _BatchUpdateIntents(IntentsRestStub): + def __hash__(self): + return hash("BatchUpdateIntents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: intent.BatchUpdateIntentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch update intents method over HTTP. + + Args: + request (~.intent.BatchUpdateIntentsRequest): + The request object. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent}/intents:batchUpdate", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent}/intents:batchUpdate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_update_intents( + request, metadata + ) + pb_request = intent.BatchUpdateIntentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_update_intents(resp) + return resp + + class _CreateIntent(IntentsRestStub): + def __hash__(self): + return hash("CreateIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_intent.CreateIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_intent.Intent: + r"""Call the create intent method over HTTP. + + Args: + request (~.gcd_intent.CreateIntentRequest): + The request object. The request message for + [Intents.CreateIntent][google.cloud.dialogflow.v2.Intents.CreateIntent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_intent.Intent: + An intent categorizes an end-user's intention for one + conversation turn. For each agent, you define many + intents, where your combined intents can handle a + complete conversation. When an end-user writes or says + something, referred to as an end-user expression or + end-user input, Dialogflow matches the end-user input to + the best intent in your agent. Matching an intent is + also known as intent classification. + + For more information, see the `intent + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent}/intents", + "body": "intent", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent}/intents", + "body": "intent", + }, + ] + request, metadata = self._interceptor.pre_create_intent(request, metadata) + pb_request = gcd_intent.CreateIntentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_intent.Intent() + pb_resp = gcd_intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_intent(resp) + return resp + + class _DeleteIntent(IntentsRestStub): + def __hash__(self): + return hash("DeleteIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: intent.DeleteIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete intent method over HTTP. + + Args: + request (~.intent.DeleteIntentRequest): + The request object. The request message for + [Intents.DeleteIntent][google.cloud.dialogflow.v2.Intents.DeleteIntent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/agent/intents/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/agent/intents/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_intent(request, metadata) + pb_request = intent.DeleteIntentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetIntent(IntentsRestStub): + def __hash__(self): + return hash("GetIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: intent.GetIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> intent.Intent: + r"""Call the get intent method over HTTP. + + Args: + request (~.intent.GetIntentRequest): + The request object. The request message for + [Intents.GetIntent][google.cloud.dialogflow.v2.Intents.GetIntent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.intent.Intent: + An intent categorizes an end-user's intention for one + conversation turn. For each agent, you define many + intents, where your combined intents can handle a + complete conversation. When an end-user writes or says + something, referred to as an end-user expression or + end-user input, Dialogflow matches the end-user input to + the best intent in your agent. Matching an intent is + also known as intent classification. + + For more information, see the `intent + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/agent/intents/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/agent/intents/*}", + }, + ] + request, metadata = self._interceptor.pre_get_intent(request, metadata) + pb_request = intent.GetIntentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = intent.Intent() + pb_resp = intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_intent(resp) + return resp + + class _ListIntents(IntentsRestStub): + def __hash__(self): + return hash("ListIntents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: intent.ListIntentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> intent.ListIntentsResponse: + r"""Call the list intents method over HTTP. + + Args: + request (~.intent.ListIntentsRequest): + The request object. The request message for + [Intents.ListIntents][google.cloud.dialogflow.v2.Intents.ListIntents]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.intent.ListIntentsResponse: + The response message for + [Intents.ListIntents][google.cloud.dialogflow.v2.Intents.ListIntents]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent}/intents", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/agent}/intents", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent/environments/*}/intents", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/agent/environments/*}/intents", + }, + ] + request, metadata = self._interceptor.pre_list_intents(request, metadata) + pb_request = intent.ListIntentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = intent.ListIntentsResponse() + pb_resp = intent.ListIntentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_intents(resp) + return resp + + class _UpdateIntent(IntentsRestStub): + def __hash__(self): + return hash("UpdateIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_intent.UpdateIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_intent.Intent: + r"""Call the update intent method over HTTP. + + Args: + request (~.gcd_intent.UpdateIntentRequest): + The request object. The request message for + [Intents.UpdateIntent][google.cloud.dialogflow.v2.Intents.UpdateIntent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_intent.Intent: + An intent categorizes an end-user's intention for one + conversation turn. For each agent, you define many + intents, where your combined intents can handle a + complete conversation. When an end-user writes or says + something, referred to as an end-user expression or + end-user input, Dialogflow matches the end-user input to + the best intent in your agent. Matching an intent is + also known as intent classification. + + For more information, see the `intent + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{intent.name=projects/*/agent/intents/*}", + "body": "intent", + }, + { + "method": "patch", + "uri": "/v2/{intent.name=projects/*/locations/*/agent/intents/*}", + "body": "intent", + }, + ] + request, metadata = self._interceptor.pre_update_intent(request, metadata) + pb_request = gcd_intent.UpdateIntentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_intent.Intent() + pb_resp = gcd_intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_intent(resp) + return resp + + @property + def batch_delete_intents( + self, + ) -> Callable[[intent.BatchDeleteIntentsRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchDeleteIntents(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_update_intents( + self, + ) -> Callable[[intent.BatchUpdateIntentsRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchUpdateIntents(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_intent( + self, + ) -> Callable[[gcd_intent.CreateIntentRequest], gcd_intent.Intent]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_intent(self) -> Callable[[intent.DeleteIntentRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_intent(self) -> Callable[[intent.GetIntentRequest], intent.Intent]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_intents( + self, + ) -> Callable[[intent.ListIntentsRequest], intent.ListIntentsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListIntents(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_intent( + self, + ) -> Callable[[gcd_intent.UpdateIntentRequest], gcd_intent.Intent]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(IntentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(IntentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(IntentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(IntentsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(IntentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("IntentsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/knowledge_bases/client.py b/google/cloud/dialogflow_v2/services/knowledge_bases/client.py index f25b807d7..dd3be6a85 100644 --- a/google/cloud/dialogflow_v2/services/knowledge_bases/client.py +++ b/google/cloud/dialogflow_v2/services/knowledge_bases/client.py @@ -57,6 +57,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, KnowledgeBasesTransport from .transports.grpc import KnowledgeBasesGrpcTransport from .transports.grpc_asyncio import KnowledgeBasesGrpcAsyncIOTransport +from .transports.rest import KnowledgeBasesRestTransport class KnowledgeBasesClientMeta(type): @@ -72,6 +73,7 @@ class KnowledgeBasesClientMeta(type): ) # type: Dict[str, Type[KnowledgeBasesTransport]] _transport_registry["grpc"] = KnowledgeBasesGrpcTransport _transport_registry["grpc_asyncio"] = KnowledgeBasesGrpcAsyncIOTransport + _transport_registry["rest"] = KnowledgeBasesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/knowledge_bases/transports/__init__.py b/google/cloud/dialogflow_v2/services/knowledge_bases/transports/__init__.py index be23a741a..285b76dcb 100644 --- a/google/cloud/dialogflow_v2/services/knowledge_bases/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/knowledge_bases/transports/__init__.py @@ -19,14 +19,18 @@ from .base import KnowledgeBasesTransport from .grpc import KnowledgeBasesGrpcTransport from .grpc_asyncio import KnowledgeBasesGrpcAsyncIOTransport +from .rest import KnowledgeBasesRestInterceptor, KnowledgeBasesRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[KnowledgeBasesTransport]] _transport_registry["grpc"] = KnowledgeBasesGrpcTransport _transport_registry["grpc_asyncio"] = KnowledgeBasesGrpcAsyncIOTransport +_transport_registry["rest"] = KnowledgeBasesRestTransport __all__ = ( "KnowledgeBasesTransport", "KnowledgeBasesGrpcTransport", "KnowledgeBasesGrpcAsyncIOTransport", + "KnowledgeBasesRestTransport", + "KnowledgeBasesRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/knowledge_bases/transports/rest.py b/google/cloud/dialogflow_v2/services/knowledge_bases/transports/rest.py new file mode 100644 index 000000000..4cd2cd7e8 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/knowledge_bases/transports/rest.py @@ -0,0 +1,1372 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import knowledge_base as gcd_knowledge_base +from google.cloud.dialogflow_v2.types import knowledge_base + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import KnowledgeBasesTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class KnowledgeBasesRestInterceptor: + """Interceptor for KnowledgeBases. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the KnowledgeBasesRestTransport. + + .. code-block:: python + class MyCustomKnowledgeBasesInterceptor(KnowledgeBasesRestInterceptor): + def pre_create_knowledge_base(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_knowledge_base(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_knowledge_base(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_knowledge_base(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_knowledge_base(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_knowledge_bases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_knowledge_bases(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_knowledge_base(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_knowledge_base(self, response): + logging.log(f"Received response: {response}") + return response + + transport = KnowledgeBasesRestTransport(interceptor=MyCustomKnowledgeBasesInterceptor()) + client = KnowledgeBasesClient(transport=transport) + + + """ + + def pre_create_knowledge_base( + self, + request: gcd_knowledge_base.CreateKnowledgeBaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_knowledge_base.CreateKnowledgeBaseRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for create_knowledge_base + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_create_knowledge_base( + self, response: gcd_knowledge_base.KnowledgeBase + ) -> gcd_knowledge_base.KnowledgeBase: + """Post-rpc interceptor for create_knowledge_base + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_delete_knowledge_base( + self, + request: knowledge_base.DeleteKnowledgeBaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[knowledge_base.DeleteKnowledgeBaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_knowledge_base + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def pre_get_knowledge_base( + self, + request: knowledge_base.GetKnowledgeBaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[knowledge_base.GetKnowledgeBaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_knowledge_base + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_get_knowledge_base( + self, response: knowledge_base.KnowledgeBase + ) -> knowledge_base.KnowledgeBase: + """Post-rpc interceptor for get_knowledge_base + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_list_knowledge_bases( + self, + request: knowledge_base.ListKnowledgeBasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[knowledge_base.ListKnowledgeBasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_knowledge_bases + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_list_knowledge_bases( + self, response: knowledge_base.ListKnowledgeBasesResponse + ) -> knowledge_base.ListKnowledgeBasesResponse: + """Post-rpc interceptor for list_knowledge_bases + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_update_knowledge_base( + self, + request: gcd_knowledge_base.UpdateKnowledgeBaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_knowledge_base.UpdateKnowledgeBaseRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for update_knowledge_base + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_update_knowledge_base( + self, response: gcd_knowledge_base.KnowledgeBase + ) -> gcd_knowledge_base.KnowledgeBase: + """Post-rpc interceptor for update_knowledge_base + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class KnowledgeBasesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: KnowledgeBasesRestInterceptor + + +class KnowledgeBasesRestTransport(KnowledgeBasesTransport): + """REST backend transport for KnowledgeBases. + + Service for managing + [KnowledgeBases][google.cloud.dialogflow.v2.KnowledgeBase]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[KnowledgeBasesRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or KnowledgeBasesRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateKnowledgeBase(KnowledgeBasesRestStub): + def __hash__(self): + return hash("CreateKnowledgeBase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_knowledge_base.CreateKnowledgeBaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_knowledge_base.KnowledgeBase: + r"""Call the create knowledge base method over HTTP. + + Args: + request (~.gcd_knowledge_base.CreateKnowledgeBaseRequest): + The request object. Request message for + [KnowledgeBases.CreateKnowledgeBase][google.cloud.dialogflow.v2.KnowledgeBases.CreateKnowledgeBase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_knowledge_base.KnowledgeBase: + A knowledge base represents a collection of knowledge + documents that you provide to Dialogflow. Your knowledge + documents contain information that may be useful during + conversations with end-users. Some Dialogflow features + use knowledge bases when looking for a response to an + end-user input. + + For more information, see the `knowledge base + guide `__. + + Note: The ``projects.agent.knowledgeBases`` resource is + deprecated; only use ``projects.knowledgeBases``. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*}/knowledgeBases", + "body": "knowledge_base", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*}/knowledgeBases", + "body": "knowledge_base", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent}/knowledgeBases", + "body": "knowledge_base", + }, + ] + request, metadata = self._interceptor.pre_create_knowledge_base( + request, metadata + ) + pb_request = gcd_knowledge_base.CreateKnowledgeBaseRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_knowledge_base.KnowledgeBase() + pb_resp = gcd_knowledge_base.KnowledgeBase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_knowledge_base(resp) + return resp + + class _DeleteKnowledgeBase(KnowledgeBasesRestStub): + def __hash__(self): + return hash("DeleteKnowledgeBase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: knowledge_base.DeleteKnowledgeBaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete knowledge base method over HTTP. + + Args: + request (~.knowledge_base.DeleteKnowledgeBaseRequest): + The request object. Request message for + [KnowledgeBases.DeleteKnowledgeBase][google.cloud.dialogflow.v2.KnowledgeBases.DeleteKnowledgeBase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/knowledgeBases/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/knowledgeBases/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/agent/knowledgeBases/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_knowledge_base( + request, metadata + ) + pb_request = knowledge_base.DeleteKnowledgeBaseRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetKnowledgeBase(KnowledgeBasesRestStub): + def __hash__(self): + return hash("GetKnowledgeBase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: knowledge_base.GetKnowledgeBaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> knowledge_base.KnowledgeBase: + r"""Call the get knowledge base method over HTTP. + + Args: + request (~.knowledge_base.GetKnowledgeBaseRequest): + The request object. Request message for + [KnowledgeBases.GetKnowledgeBase][google.cloud.dialogflow.v2.KnowledgeBases.GetKnowledgeBase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.knowledge_base.KnowledgeBase: + A knowledge base represents a collection of knowledge + documents that you provide to Dialogflow. Your knowledge + documents contain information that may be useful during + conversations with end-users. Some Dialogflow features + use knowledge bases when looking for a response to an + end-user input. + + For more information, see the `knowledge base + guide `__. + + Note: The ``projects.agent.knowledgeBases`` resource is + deprecated; only use ``projects.knowledgeBases``. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/knowledgeBases/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/knowledgeBases/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/agent/knowledgeBases/*}", + }, + ] + request, metadata = self._interceptor.pre_get_knowledge_base( + request, metadata + ) + pb_request = knowledge_base.GetKnowledgeBaseRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = knowledge_base.KnowledgeBase() + pb_resp = knowledge_base.KnowledgeBase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_knowledge_base(resp) + return resp + + class _ListKnowledgeBases(KnowledgeBasesRestStub): + def __hash__(self): + return hash("ListKnowledgeBases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: knowledge_base.ListKnowledgeBasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> knowledge_base.ListKnowledgeBasesResponse: + r"""Call the list knowledge bases method over HTTP. + + Args: + request (~.knowledge_base.ListKnowledgeBasesRequest): + The request object. Request message for + [KnowledgeBases.ListKnowledgeBases][google.cloud.dialogflow.v2.KnowledgeBases.ListKnowledgeBases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.knowledge_base.ListKnowledgeBasesResponse: + Response message for + [KnowledgeBases.ListKnowledgeBases][google.cloud.dialogflow.v2.KnowledgeBases.ListKnowledgeBases]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*}/knowledgeBases", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*}/knowledgeBases", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent}/knowledgeBases", + }, + ] + request, metadata = self._interceptor.pre_list_knowledge_bases( + request, metadata + ) + pb_request = knowledge_base.ListKnowledgeBasesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = knowledge_base.ListKnowledgeBasesResponse() + pb_resp = knowledge_base.ListKnowledgeBasesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_knowledge_bases(resp) + return resp + + class _UpdateKnowledgeBase(KnowledgeBasesRestStub): + def __hash__(self): + return hash("UpdateKnowledgeBase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_knowledge_base.UpdateKnowledgeBaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_knowledge_base.KnowledgeBase: + r"""Call the update knowledge base method over HTTP. + + Args: + request (~.gcd_knowledge_base.UpdateKnowledgeBaseRequest): + The request object. Request message for + [KnowledgeBases.UpdateKnowledgeBase][google.cloud.dialogflow.v2.KnowledgeBases.UpdateKnowledgeBase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_knowledge_base.KnowledgeBase: + A knowledge base represents a collection of knowledge + documents that you provide to Dialogflow. Your knowledge + documents contain information that may be useful during + conversations with end-users. Some Dialogflow features + use knowledge bases when looking for a response to an + end-user input. + + For more information, see the `knowledge base + guide `__. + + Note: The ``projects.agent.knowledgeBases`` resource is + deprecated; only use ``projects.knowledgeBases``. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{knowledge_base.name=projects/*/knowledgeBases/*}", + "body": "knowledge_base", + }, + { + "method": "patch", + "uri": "/v2/{knowledge_base.name=projects/*/locations/*/knowledgeBases/*}", + "body": "knowledge_base", + }, + { + "method": "patch", + "uri": "/v2/{knowledge_base.name=projects/*/agent/knowledgeBases/*}", + "body": "knowledge_base", + }, + ] + request, metadata = self._interceptor.pre_update_knowledge_base( + request, metadata + ) + pb_request = gcd_knowledge_base.UpdateKnowledgeBaseRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_knowledge_base.KnowledgeBase() + pb_resp = gcd_knowledge_base.KnowledgeBase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_knowledge_base(resp) + return resp + + @property + def create_knowledge_base( + self, + ) -> Callable[ + [gcd_knowledge_base.CreateKnowledgeBaseRequest], + gcd_knowledge_base.KnowledgeBase, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateKnowledgeBase(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_knowledge_base( + self, + ) -> Callable[[knowledge_base.DeleteKnowledgeBaseRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteKnowledgeBase(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_knowledge_base( + self, + ) -> Callable[ + [knowledge_base.GetKnowledgeBaseRequest], knowledge_base.KnowledgeBase + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetKnowledgeBase(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_knowledge_bases( + self, + ) -> Callable[ + [knowledge_base.ListKnowledgeBasesRequest], + knowledge_base.ListKnowledgeBasesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListKnowledgeBases(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_knowledge_base( + self, + ) -> Callable[ + [gcd_knowledge_base.UpdateKnowledgeBaseRequest], + gcd_knowledge_base.KnowledgeBase, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateKnowledgeBase(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(KnowledgeBasesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(KnowledgeBasesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(KnowledgeBasesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(KnowledgeBasesRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(KnowledgeBasesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("KnowledgeBasesRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/participants/client.py b/google/cloud/dialogflow_v2/services/participants/client.py index d266a992a..2df2314cb 100644 --- a/google/cloud/dialogflow_v2/services/participants/client.py +++ b/google/cloud/dialogflow_v2/services/participants/client.py @@ -60,6 +60,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, ParticipantsTransport from .transports.grpc import ParticipantsGrpcTransport from .transports.grpc_asyncio import ParticipantsGrpcAsyncIOTransport +from .transports.rest import ParticipantsRestTransport class ParticipantsClientMeta(type): @@ -73,6 +74,7 @@ class ParticipantsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[ParticipantsTransport]] _transport_registry["grpc"] = ParticipantsGrpcTransport _transport_registry["grpc_asyncio"] = ParticipantsGrpcAsyncIOTransport + _transport_registry["rest"] = ParticipantsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/participants/transports/__init__.py b/google/cloud/dialogflow_v2/services/participants/transports/__init__.py index 05e4f7615..393948ada 100644 --- a/google/cloud/dialogflow_v2/services/participants/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/participants/transports/__init__.py @@ -19,14 +19,18 @@ from .base import ParticipantsTransport from .grpc import ParticipantsGrpcTransport from .grpc_asyncio import ParticipantsGrpcAsyncIOTransport +from .rest import ParticipantsRestInterceptor, ParticipantsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[ParticipantsTransport]] _transport_registry["grpc"] = ParticipantsGrpcTransport _transport_registry["grpc_asyncio"] = ParticipantsGrpcAsyncIOTransport +_transport_registry["rest"] = ParticipantsRestTransport __all__ = ( "ParticipantsTransport", "ParticipantsGrpcTransport", "ParticipantsGrpcAsyncIOTransport", + "ParticipantsRestTransport", + "ParticipantsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/participants/transports/rest.py b/google/cloud/dialogflow_v2/services/participants/transports/rest.py new file mode 100644 index 000000000..cc66544c4 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/participants/transports/rest.py @@ -0,0 +1,1817 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.dialogflow_v2.types import participant +from google.cloud.dialogflow_v2.types import participant as gcd_participant + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import ParticipantsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class ParticipantsRestInterceptor: + """Interceptor for Participants. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the ParticipantsRestTransport. + + .. code-block:: python + class MyCustomParticipantsInterceptor(ParticipantsRestInterceptor): + def pre_analyze_content(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_analyze_content(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_participant(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_participant(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_participant(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_participant(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_participants(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_participants(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_suggest_articles(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_suggest_articles(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_suggest_faq_answers(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_suggest_faq_answers(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_suggest_smart_replies(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_suggest_smart_replies(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_participant(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_participant(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ParticipantsRestTransport(interceptor=MyCustomParticipantsInterceptor()) + client = ParticipantsClient(transport=transport) + + + """ + + def pre_analyze_content( + self, + request: gcd_participant.AnalyzeContentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_participant.AnalyzeContentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for analyze_content + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_analyze_content( + self, response: gcd_participant.AnalyzeContentResponse + ) -> gcd_participant.AnalyzeContentResponse: + """Post-rpc interceptor for analyze_content + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_create_participant( + self, + request: gcd_participant.CreateParticipantRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_participant.CreateParticipantRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_participant + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_create_participant( + self, response: gcd_participant.Participant + ) -> gcd_participant.Participant: + """Post-rpc interceptor for create_participant + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_get_participant( + self, + request: participant.GetParticipantRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.GetParticipantRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_participant + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_get_participant( + self, response: participant.Participant + ) -> participant.Participant: + """Post-rpc interceptor for get_participant + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_list_participants( + self, + request: participant.ListParticipantsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.ListParticipantsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_participants + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_list_participants( + self, response: participant.ListParticipantsResponse + ) -> participant.ListParticipantsResponse: + """Post-rpc interceptor for list_participants + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_suggest_articles( + self, + request: participant.SuggestArticlesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.SuggestArticlesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for suggest_articles + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_suggest_articles( + self, response: participant.SuggestArticlesResponse + ) -> participant.SuggestArticlesResponse: + """Post-rpc interceptor for suggest_articles + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_suggest_faq_answers( + self, + request: participant.SuggestFaqAnswersRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.SuggestFaqAnswersRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for suggest_faq_answers + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_suggest_faq_answers( + self, response: participant.SuggestFaqAnswersResponse + ) -> participant.SuggestFaqAnswersResponse: + """Post-rpc interceptor for suggest_faq_answers + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_suggest_smart_replies( + self, + request: participant.SuggestSmartRepliesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.SuggestSmartRepliesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for suggest_smart_replies + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_suggest_smart_replies( + self, response: participant.SuggestSmartRepliesResponse + ) -> participant.SuggestSmartRepliesResponse: + """Post-rpc interceptor for suggest_smart_replies + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_update_participant( + self, + request: gcd_participant.UpdateParticipantRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_participant.UpdateParticipantRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_participant + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_update_participant( + self, response: gcd_participant.Participant + ) -> gcd_participant.Participant: + """Post-rpc interceptor for update_participant + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ParticipantsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ParticipantsRestInterceptor + + +class ParticipantsRestTransport(ParticipantsTransport): + """REST backend transport for Participants. + + Service for managing + [Participants][google.cloud.dialogflow.v2.Participant]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[ParticipantsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or ParticipantsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _AnalyzeContent(ParticipantsRestStub): + def __hash__(self): + return hash("AnalyzeContent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_participant.AnalyzeContentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_participant.AnalyzeContentResponse: + r"""Call the analyze content method over HTTP. + + Args: + request (~.gcd_participant.AnalyzeContentRequest): + The request object. The request message for + [Participants.AnalyzeContent][google.cloud.dialogflow.v2.Participants.AnalyzeContent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_participant.AnalyzeContentResponse: + The response message for + [Participants.AnalyzeContent][google.cloud.dialogflow.v2.Participants.AnalyzeContent]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{participant=projects/*/conversations/*/participants/*}:analyzeContent", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{participant=projects/*/locations/*/conversations/*/participants/*}:analyzeContent", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_analyze_content(request, metadata) + pb_request = gcd_participant.AnalyzeContentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_participant.AnalyzeContentResponse() + pb_resp = gcd_participant.AnalyzeContentResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_analyze_content(resp) + return resp + + class _CreateParticipant(ParticipantsRestStub): + def __hash__(self): + return hash("CreateParticipant") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_participant.CreateParticipantRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_participant.Participant: + r"""Call the create participant method over HTTP. + + Args: + request (~.gcd_participant.CreateParticipantRequest): + The request object. The request message for + [Participants.CreateParticipant][google.cloud.dialogflow.v2.Participants.CreateParticipant]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_participant.Participant: + Represents a conversation participant + (human agent, virtual agent, end-user). + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/conversations/*}/participants", + "body": "participant", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/conversations/*}/participants", + "body": "participant", + }, + ] + request, metadata = self._interceptor.pre_create_participant( + request, metadata + ) + pb_request = gcd_participant.CreateParticipantRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_participant.Participant() + pb_resp = gcd_participant.Participant.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_participant(resp) + return resp + + class _GetParticipant(ParticipantsRestStub): + def __hash__(self): + return hash("GetParticipant") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: participant.GetParticipantRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.Participant: + r"""Call the get participant method over HTTP. + + Args: + request (~.participant.GetParticipantRequest): + The request object. The request message for + [Participants.GetParticipant][google.cloud.dialogflow.v2.Participants.GetParticipant]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.Participant: + Represents a conversation participant + (human agent, virtual agent, end-user). + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/conversations/*/participants/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/conversations/*/participants/*}", + }, + ] + request, metadata = self._interceptor.pre_get_participant(request, metadata) + pb_request = participant.GetParticipantRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.Participant() + pb_resp = participant.Participant.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_participant(resp) + return resp + + class _ListParticipants(ParticipantsRestStub): + def __hash__(self): + return hash("ListParticipants") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: participant.ListParticipantsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.ListParticipantsResponse: + r"""Call the list participants method over HTTP. + + Args: + request (~.participant.ListParticipantsRequest): + The request object. The request message for + [Participants.ListParticipants][google.cloud.dialogflow.v2.Participants.ListParticipants]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.ListParticipantsResponse: + The response message for + [Participants.ListParticipants][google.cloud.dialogflow.v2.Participants.ListParticipants]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/conversations/*}/participants", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/conversations/*}/participants", + }, + ] + request, metadata = self._interceptor.pre_list_participants( + request, metadata + ) + pb_request = participant.ListParticipantsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.ListParticipantsResponse() + pb_resp = participant.ListParticipantsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_participants(resp) + return resp + + class _StreamingAnalyzeContent(ParticipantsRestStub): + def __hash__(self): + return hash("StreamingAnalyzeContent") + + def __call__( + self, + request: participant.StreamingAnalyzeContentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> rest_streaming.ResponseIterator: + raise NotImplementedError( + "Method StreamingAnalyzeContent is not available over REST transport" + ) + + class _SuggestArticles(ParticipantsRestStub): + def __hash__(self): + return hash("SuggestArticles") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: participant.SuggestArticlesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.SuggestArticlesResponse: + r"""Call the suggest articles method over HTTP. + + Args: + request (~.participant.SuggestArticlesRequest): + The request object. The request message for + [Participants.SuggestArticles][google.cloud.dialogflow.v2.Participants.SuggestArticles]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.SuggestArticlesResponse: + The response message for + [Participants.SuggestArticles][google.cloud.dialogflow.v2.Participants.SuggestArticles]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestArticles", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/conversations/*/participants/*}/suggestions:suggestArticles", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_suggest_articles( + request, metadata + ) + pb_request = participant.SuggestArticlesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.SuggestArticlesResponse() + pb_resp = participant.SuggestArticlesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_suggest_articles(resp) + return resp + + class _SuggestFaqAnswers(ParticipantsRestStub): + def __hash__(self): + return hash("SuggestFaqAnswers") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: participant.SuggestFaqAnswersRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.SuggestFaqAnswersResponse: + r"""Call the suggest faq answers method over HTTP. + + Args: + request (~.participant.SuggestFaqAnswersRequest): + The request object. The request message for + [Participants.SuggestFaqAnswers][google.cloud.dialogflow.v2.Participants.SuggestFaqAnswers]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.SuggestFaqAnswersResponse: + The request message for + [Participants.SuggestFaqAnswers][google.cloud.dialogflow.v2.Participants.SuggestFaqAnswers]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestFaqAnswers", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/conversations/*/participants/*}/suggestions:suggestFaqAnswers", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_suggest_faq_answers( + request, metadata + ) + pb_request = participant.SuggestFaqAnswersRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.SuggestFaqAnswersResponse() + pb_resp = participant.SuggestFaqAnswersResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_suggest_faq_answers(resp) + return resp + + class _SuggestSmartReplies(ParticipantsRestStub): + def __hash__(self): + return hash("SuggestSmartReplies") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: participant.SuggestSmartRepliesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.SuggestSmartRepliesResponse: + r"""Call the suggest smart replies method over HTTP. + + Args: + request (~.participant.SuggestSmartRepliesRequest): + The request object. The request message for + [Participants.SuggestSmartReplies][google.cloud.dialogflow.v2.Participants.SuggestSmartReplies]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.SuggestSmartRepliesResponse: + The response message for + [Participants.SuggestSmartReplies][google.cloud.dialogflow.v2.Participants.SuggestSmartReplies]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestSmartReplies", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/conversations/*/participants/*}/suggestions:suggestSmartReplies", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_suggest_smart_replies( + request, metadata + ) + pb_request = participant.SuggestSmartRepliesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.SuggestSmartRepliesResponse() + pb_resp = participant.SuggestSmartRepliesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_suggest_smart_replies(resp) + return resp + + class _UpdateParticipant(ParticipantsRestStub): + def __hash__(self): + return hash("UpdateParticipant") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_participant.UpdateParticipantRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_participant.Participant: + r"""Call the update participant method over HTTP. + + Args: + request (~.gcd_participant.UpdateParticipantRequest): + The request object. The request message for + [Participants.UpdateParticipant][google.cloud.dialogflow.v2.Participants.UpdateParticipant]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_participant.Participant: + Represents a conversation participant + (human agent, virtual agent, end-user). + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{participant.name=projects/*/conversations/*/participants/*}", + "body": "participant", + }, + { + "method": "patch", + "uri": "/v2/{participant.name=projects/*/locations/*/conversations/*/participants/*}", + "body": "participant", + }, + ] + request, metadata = self._interceptor.pre_update_participant( + request, metadata + ) + pb_request = gcd_participant.UpdateParticipantRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_participant.Participant() + pb_resp = gcd_participant.Participant.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_participant(resp) + return resp + + @property + def analyze_content( + self, + ) -> Callable[ + [gcd_participant.AnalyzeContentRequest], gcd_participant.AnalyzeContentResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._AnalyzeContent(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_participant( + self, + ) -> Callable[ + [gcd_participant.CreateParticipantRequest], gcd_participant.Participant + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateParticipant(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_participant( + self, + ) -> Callable[[participant.GetParticipantRequest], participant.Participant]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetParticipant(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_participants( + self, + ) -> Callable[ + [participant.ListParticipantsRequest], participant.ListParticipantsResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListParticipants(self._session, self._host, self._interceptor) # type: ignore + + @property + def streaming_analyze_content( + self, + ) -> Callable[ + [participant.StreamingAnalyzeContentRequest], + participant.StreamingAnalyzeContentResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._StreamingAnalyzeContent(self._session, self._host, self._interceptor) # type: ignore + + @property + def suggest_articles( + self, + ) -> Callable[ + [participant.SuggestArticlesRequest], participant.SuggestArticlesResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SuggestArticles(self._session, self._host, self._interceptor) # type: ignore + + @property + def suggest_faq_answers( + self, + ) -> Callable[ + [participant.SuggestFaqAnswersRequest], participant.SuggestFaqAnswersResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SuggestFaqAnswers(self._session, self._host, self._interceptor) # type: ignore + + @property + def suggest_smart_replies( + self, + ) -> Callable[ + [participant.SuggestSmartRepliesRequest], + participant.SuggestSmartRepliesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SuggestSmartReplies(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_participant( + self, + ) -> Callable[ + [gcd_participant.UpdateParticipantRequest], gcd_participant.Participant + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateParticipant(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ParticipantsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ParticipantsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ParticipantsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ParticipantsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ParticipantsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ParticipantsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/session_entity_types/client.py b/google/cloud/dialogflow_v2/services/session_entity_types/client.py index f012f1f61..70f499cc7 100644 --- a/google/cloud/dialogflow_v2/services/session_entity_types/client.py +++ b/google/cloud/dialogflow_v2/services/session_entity_types/client.py @@ -60,6 +60,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, SessionEntityTypesTransport from .transports.grpc import SessionEntityTypesGrpcTransport from .transports.grpc_asyncio import SessionEntityTypesGrpcAsyncIOTransport +from .transports.rest import SessionEntityTypesRestTransport class SessionEntityTypesClientMeta(type): @@ -75,6 +76,7 @@ class SessionEntityTypesClientMeta(type): ) # type: Dict[str, Type[SessionEntityTypesTransport]] _transport_registry["grpc"] = SessionEntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = SessionEntityTypesGrpcAsyncIOTransport + _transport_registry["rest"] = SessionEntityTypesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/session_entity_types/transports/__init__.py b/google/cloud/dialogflow_v2/services/session_entity_types/transports/__init__.py index d21afca4f..9dfccaa53 100644 --- a/google/cloud/dialogflow_v2/services/session_entity_types/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/session_entity_types/transports/__init__.py @@ -19,6 +19,7 @@ from .base import SessionEntityTypesTransport from .grpc import SessionEntityTypesGrpcTransport from .grpc_asyncio import SessionEntityTypesGrpcAsyncIOTransport +from .rest import SessionEntityTypesRestInterceptor, SessionEntityTypesRestTransport # Compile a registry of transports. _transport_registry = ( @@ -26,9 +27,12 @@ ) # type: Dict[str, Type[SessionEntityTypesTransport]] _transport_registry["grpc"] = SessionEntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = SessionEntityTypesGrpcAsyncIOTransport +_transport_registry["rest"] = SessionEntityTypesRestTransport __all__ = ( "SessionEntityTypesTransport", "SessionEntityTypesGrpcTransport", "SessionEntityTypesGrpcAsyncIOTransport", + "SessionEntityTypesRestTransport", + "SessionEntityTypesRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/session_entity_types/transports/rest.py b/google/cloud/dialogflow_v2/services/session_entity_types/transports/rest.py new file mode 100644 index 000000000..92016e826 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/session_entity_types/transports/rest.py @@ -0,0 +1,1408 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import ( + session_entity_type as gcd_session_entity_type, +) +from google.cloud.dialogflow_v2.types import session_entity_type + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import SessionEntityTypesTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class SessionEntityTypesRestInterceptor: + """Interceptor for SessionEntityTypes. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the SessionEntityTypesRestTransport. + + .. code-block:: python + class MyCustomSessionEntityTypesInterceptor(SessionEntityTypesRestInterceptor): + def pre_create_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_session_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_session_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + transport = SessionEntityTypesRestTransport(interceptor=MyCustomSessionEntityTypesInterceptor()) + client = SessionEntityTypesClient(transport=transport) + + + """ + + def pre_create_session_entity_type( + self, + request: gcd_session_entity_type.CreateSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_session_entity_type.CreateSessionEntityTypeRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for create_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_create_session_entity_type( + self, response: gcd_session_entity_type.SessionEntityType + ) -> gcd_session_entity_type.SessionEntityType: + """Post-rpc interceptor for create_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_delete_session_entity_type( + self, + request: session_entity_type.DeleteSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.DeleteSessionEntityTypeRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for delete_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def pre_get_session_entity_type( + self, + request: session_entity_type.GetSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.GetSessionEntityTypeRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for get_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_session_entity_type( + self, response: session_entity_type.SessionEntityType + ) -> session_entity_type.SessionEntityType: + """Post-rpc interceptor for get_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_session_entity_types( + self, + request: session_entity_type.ListSessionEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.ListSessionEntityTypesRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for list_session_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_session_entity_types( + self, response: session_entity_type.ListSessionEntityTypesResponse + ) -> session_entity_type.ListSessionEntityTypesResponse: + """Post-rpc interceptor for list_session_entity_types + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_update_session_entity_type( + self, + request: gcd_session_entity_type.UpdateSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_session_entity_type.UpdateSessionEntityTypeRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for update_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_update_session_entity_type( + self, response: gcd_session_entity_type.SessionEntityType + ) -> gcd_session_entity_type.SessionEntityType: + """Post-rpc interceptor for update_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class SessionEntityTypesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: SessionEntityTypesRestInterceptor + + +class SessionEntityTypesRestTransport(SessionEntityTypesTransport): + """REST backend transport for SessionEntityTypes. + + Service for managing + [SessionEntityTypes][google.cloud.dialogflow.v2.SessionEntityType]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[SessionEntityTypesRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or SessionEntityTypesRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("CreateSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_session_entity_type.CreateSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_session_entity_type.SessionEntityType: + r"""Call the create session entity + type method over HTTP. + + Args: + request (~.gcd_session_entity_type.CreateSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.CreateSessionEntityType][google.cloud.dialogflow.v2.SessionEntityTypes.CreateSessionEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_session_entity_type.SessionEntityType: + A session represents a conversation between a Dialogflow + agent and an end-user. You can create special entities, + called session entities, during a session. Session + entities can extend or replace custom entity types and + only exist during the session that they were created + for. All session data, including session entities, is + stored by Dialogflow for 20 minutes. + + For more information, see the `session entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent/environments/*/users/*/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent/environments/*/users/*/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + ] + request, metadata = self._interceptor.pre_create_session_entity_type( + request, metadata + ) + pb_request = gcd_session_entity_type.CreateSessionEntityTypeRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_session_entity_type.SessionEntityType() + pb_resp = gcd_session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_session_entity_type(resp) + return resp + + class _DeleteSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("DeleteSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: session_entity_type.DeleteSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete session entity + type method over HTTP. + + Args: + request (~.session_entity_type.DeleteSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.DeleteSessionEntityType][google.cloud.dialogflow.v2.SessionEntityTypes.DeleteSessionEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/agent/sessions/*/entityTypes/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/agent/sessions/*/entityTypes/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_session_entity_type( + request, metadata + ) + pb_request = session_entity_type.DeleteSessionEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("GetSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: session_entity_type.GetSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session_entity_type.SessionEntityType: + r"""Call the get session entity type method over HTTP. + + Args: + request (~.session_entity_type.GetSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.GetSessionEntityType][google.cloud.dialogflow.v2.SessionEntityTypes.GetSessionEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.session_entity_type.SessionEntityType: + A session represents a conversation between a Dialogflow + agent and an end-user. You can create special entities, + called session entities, during a session. Session + entities can extend or replace custom entity types and + only exist during the session that they were created + for. All session data, including session entities, is + stored by Dialogflow for 20 minutes. + + For more information, see the `session entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/agent/sessions/*/entityTypes/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/agent/sessions/*/entityTypes/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_get_session_entity_type( + request, metadata + ) + pb_request = session_entity_type.GetSessionEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = session_entity_type.SessionEntityType() + pb_resp = session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_session_entity_type(resp) + return resp + + class _ListSessionEntityTypes(SessionEntityTypesRestStub): + def __hash__(self): + return hash("ListSessionEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: session_entity_type.ListSessionEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session_entity_type.ListSessionEntityTypesResponse: + r"""Call the list session entity types method over HTTP. + + Args: + request (~.session_entity_type.ListSessionEntityTypesRequest): + The request object. The request message for + [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.v2.SessionEntityTypes.ListSessionEntityTypes]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.session_entity_type.ListSessionEntityTypesResponse: + The response message for + [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.v2.SessionEntityTypes.ListSessionEntityTypes]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent/sessions/*}/entityTypes", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent/environments/*/users/*/sessions/*}/entityTypes", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/agent/sessions/*}/entityTypes", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/agent/environments/*/users/*/sessions/*}/entityTypes", + }, + ] + request, metadata = self._interceptor.pre_list_session_entity_types( + request, metadata + ) + pb_request = session_entity_type.ListSessionEntityTypesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = session_entity_type.ListSessionEntityTypesResponse() + pb_resp = session_entity_type.ListSessionEntityTypesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_session_entity_types(resp) + return resp + + class _UpdateSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("UpdateSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_session_entity_type.UpdateSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_session_entity_type.SessionEntityType: + r"""Call the update session entity + type method over HTTP. + + Args: + request (~.gcd_session_entity_type.UpdateSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.UpdateSessionEntityType][google.cloud.dialogflow.v2.SessionEntityTypes.UpdateSessionEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_session_entity_type.SessionEntityType: + A session represents a conversation between a Dialogflow + agent and an end-user. You can create special entities, + called session entities, during a session. Session + entities can extend or replace custom entity types and + only exist during the session that they were created + for. All session data, including session entities, is + stored by Dialogflow for 20 minutes. + + For more information, see the `session entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{session_entity_type.name=projects/*/agent/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + { + "method": "patch", + "uri": "/v2/{session_entity_type.name=projects/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + { + "method": "patch", + "uri": "/v2/{session_entity_type.name=projects/*/locations/*/agent/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + { + "method": "patch", + "uri": "/v2/{session_entity_type.name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + ] + request, metadata = self._interceptor.pre_update_session_entity_type( + request, metadata + ) + pb_request = gcd_session_entity_type.UpdateSessionEntityTypeRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_session_entity_type.SessionEntityType() + pb_resp = gcd_session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_session_entity_type(resp) + return resp + + @property + def create_session_entity_type( + self, + ) -> Callable[ + [gcd_session_entity_type.CreateSessionEntityTypeRequest], + gcd_session_entity_type.SessionEntityType, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_session_entity_type( + self, + ) -> Callable[ + [session_entity_type.DeleteSessionEntityTypeRequest], empty_pb2.Empty + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_session_entity_type( + self, + ) -> Callable[ + [session_entity_type.GetSessionEntityTypeRequest], + session_entity_type.SessionEntityType, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_session_entity_types( + self, + ) -> Callable[ + [session_entity_type.ListSessionEntityTypesRequest], + session_entity_type.ListSessionEntityTypesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListSessionEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_session_entity_type( + self, + ) -> Callable[ + [gcd_session_entity_type.UpdateSessionEntityTypeRequest], + gcd_session_entity_type.SessionEntityType, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(SessionEntityTypesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(SessionEntityTypesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(SessionEntityTypesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(SessionEntityTypesRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(SessionEntityTypesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("SessionEntityTypesRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/sessions/client.py b/google/cloud/dialogflow_v2/services/sessions/client.py index ad1c918ad..ec807833a 100644 --- a/google/cloud/dialogflow_v2/services/sessions/client.py +++ b/google/cloud/dialogflow_v2/services/sessions/client.py @@ -59,6 +59,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, SessionsTransport from .transports.grpc import SessionsGrpcTransport from .transports.grpc_asyncio import SessionsGrpcAsyncIOTransport +from .transports.rest import SessionsRestTransport class SessionsClientMeta(type): @@ -72,6 +73,7 @@ class SessionsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[SessionsTransport]] _transport_registry["grpc"] = SessionsGrpcTransport _transport_registry["grpc_asyncio"] = SessionsGrpcAsyncIOTransport + _transport_registry["rest"] = SessionsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/sessions/transports/__init__.py b/google/cloud/dialogflow_v2/services/sessions/transports/__init__.py index 72ba9b72a..27547f74a 100644 --- a/google/cloud/dialogflow_v2/services/sessions/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/sessions/transports/__init__.py @@ -19,14 +19,18 @@ from .base import SessionsTransport from .grpc import SessionsGrpcTransport from .grpc_asyncio import SessionsGrpcAsyncIOTransport +from .rest import SessionsRestInterceptor, SessionsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[SessionsTransport]] _transport_registry["grpc"] = SessionsGrpcTransport _transport_registry["grpc_asyncio"] = SessionsGrpcAsyncIOTransport +_transport_registry["rest"] = SessionsRestTransport __all__ = ( "SessionsTransport", "SessionsGrpcTransport", "SessionsGrpcAsyncIOTransport", + "SessionsRestTransport", + "SessionsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/sessions/transports/rest.py b/google/cloud/dialogflow_v2/services/sessions/transports/rest.py new file mode 100644 index 000000000..2a3a6f4f1 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/sessions/transports/rest.py @@ -0,0 +1,816 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.dialogflow_v2.types import session +from google.cloud.dialogflow_v2.types import session as gcd_session + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import SessionsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class SessionsRestInterceptor: + """Interceptor for Sessions. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the SessionsRestTransport. + + .. code-block:: python + class MyCustomSessionsInterceptor(SessionsRestInterceptor): + def pre_detect_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_detect_intent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = SessionsRestTransport(interceptor=MyCustomSessionsInterceptor()) + client = SessionsClient(transport=transport) + + + """ + + def pre_detect_intent( + self, + request: gcd_session.DetectIntentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_session.DetectIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for detect_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_detect_intent( + self, response: gcd_session.DetectIntentResponse + ) -> gcd_session.DetectIntentResponse: + """Post-rpc interceptor for detect_intent + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class SessionsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: SessionsRestInterceptor + + +class SessionsRestTransport(SessionsTransport): + """REST backend transport for Sessions. + + A service used for session interactions. + + For more information, see the `API interactions + guide `__. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[SessionsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or SessionsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _DetectIntent(SessionsRestStub): + def __hash__(self): + return hash("DetectIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_session.DetectIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_session.DetectIntentResponse: + r"""Call the detect intent method over HTTP. + + Args: + request (~.gcd_session.DetectIntentRequest): + The request object. The request to detect user's intent. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_session.DetectIntentResponse: + The message returned from the + DetectIntent method. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{session=projects/*/agent/sessions/*}:detectIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{session=projects/*/agent/environments/*/users/*/sessions/*}:detectIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{session=projects/*/locations/*/agent/sessions/*}:detectIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v2/{session=projects/*/locations/*/agent/environments/*/users/*/sessions/*}:detectIntent", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_detect_intent(request, metadata) + pb_request = gcd_session.DetectIntentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_session.DetectIntentResponse() + pb_resp = gcd_session.DetectIntentResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_detect_intent(resp) + return resp + + class _StreamingDetectIntent(SessionsRestStub): + def __hash__(self): + return hash("StreamingDetectIntent") + + def __call__( + self, + request: session.StreamingDetectIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> rest_streaming.ResponseIterator: + raise NotImplementedError( + "Method StreamingDetectIntent is not available over REST transport" + ) + + @property + def detect_intent( + self, + ) -> Callable[[gcd_session.DetectIntentRequest], gcd_session.DetectIntentResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DetectIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def streaming_detect_intent( + self, + ) -> Callable[ + [session.StreamingDetectIntentRequest], session.StreamingDetectIntentResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._StreamingDetectIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(SessionsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(SessionsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(SessionsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(SessionsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(SessionsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("SessionsRestTransport",) diff --git a/google/cloud/dialogflow_v2/services/versions/client.py b/google/cloud/dialogflow_v2/services/versions/client.py index ccdd50d0e..275463657 100644 --- a/google/cloud/dialogflow_v2/services/versions/client.py +++ b/google/cloud/dialogflow_v2/services/versions/client.py @@ -58,6 +58,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, VersionsTransport from .transports.grpc import VersionsGrpcTransport from .transports.grpc_asyncio import VersionsGrpcAsyncIOTransport +from .transports.rest import VersionsRestTransport class VersionsClientMeta(type): @@ -71,6 +72,7 @@ class VersionsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[VersionsTransport]] _transport_registry["grpc"] = VersionsGrpcTransport _transport_registry["grpc_asyncio"] = VersionsGrpcAsyncIOTransport + _transport_registry["rest"] = VersionsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2/services/versions/transports/__init__.py b/google/cloud/dialogflow_v2/services/versions/transports/__init__.py index e31c2163a..e921ca1d4 100644 --- a/google/cloud/dialogflow_v2/services/versions/transports/__init__.py +++ b/google/cloud/dialogflow_v2/services/versions/transports/__init__.py @@ -19,14 +19,18 @@ from .base import VersionsTransport from .grpc import VersionsGrpcTransport from .grpc_asyncio import VersionsGrpcAsyncIOTransport +from .rest import VersionsRestInterceptor, VersionsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[VersionsTransport]] _transport_registry["grpc"] = VersionsGrpcTransport _transport_registry["grpc_asyncio"] = VersionsGrpcAsyncIOTransport +_transport_registry["rest"] = VersionsRestTransport __all__ = ( "VersionsTransport", "VersionsGrpcTransport", "VersionsGrpcAsyncIOTransport", + "VersionsRestTransport", + "VersionsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2/services/versions/transports/rest.py b/google/cloud/dialogflow_v2/services/versions/transports/rest.py new file mode 100644 index 000000000..b89c13d70 --- /dev/null +++ b/google/cloud/dialogflow_v2/services/versions/transports/rest.py @@ -0,0 +1,1333 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2.types import version +from google.cloud.dialogflow_v2.types import version as gcd_version + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import VersionsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class VersionsRestInterceptor: + """Interceptor for Versions. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the VersionsRestTransport. + + .. code-block:: python + class MyCustomVersionsInterceptor(VersionsRestInterceptor): + def pre_create_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_version(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_version(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_versions(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_versions(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_version(self, response): + logging.log(f"Received response: {response}") + return response + + transport = VersionsRestTransport(interceptor=MyCustomVersionsInterceptor()) + client = VersionsClient(transport=transport) + + + """ + + def pre_create_version( + self, + request: gcd_version.CreateVersionRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_version.CreateVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_create_version(self, response: gcd_version.Version) -> gcd_version.Version: + """Post-rpc interceptor for create_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_delete_version( + self, request: version.DeleteVersionRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.DeleteVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def pre_get_version( + self, request: version.GetVersionRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.GetVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_version(self, response: version.Version) -> version.Version: + """Post-rpc interceptor for get_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_versions( + self, request: version.ListVersionsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.ListVersionsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_versions + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_versions( + self, response: version.ListVersionsResponse + ) -> version.ListVersionsResponse: + """Post-rpc interceptor for list_versions + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_update_version( + self, + request: gcd_version.UpdateVersionRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_version.UpdateVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_update_version(self, response: gcd_version.Version) -> gcd_version.Version: + """Post-rpc interceptor for update_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class VersionsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: VersionsRestInterceptor + + +class VersionsRestTransport(VersionsTransport): + """REST backend transport for Versions. + + Service for managing [Versions][google.cloud.dialogflow.v2.Version]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[VersionsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or VersionsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateVersion(VersionsRestStub): + def __hash__(self): + return hash("CreateVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_version.CreateVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_version.Version: + r"""Call the create version method over HTTP. + + Args: + request (~.gcd_version.CreateVersionRequest): + The request object. The request message for + [Versions.CreateVersion][google.cloud.dialogflow.v2.Versions.CreateVersion]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_version.Version: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{parent=projects/*/agent}/versions", + "body": "version", + }, + { + "method": "post", + "uri": "/v2/{parent=projects/*/locations/*/agent}/versions", + "body": "version", + }, + ] + request, metadata = self._interceptor.pre_create_version(request, metadata) + pb_request = gcd_version.CreateVersionRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_version.Version() + pb_resp = gcd_version.Version.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_version(resp) + return resp + + class _DeleteVersion(VersionsRestStub): + def __hash__(self): + return hash("DeleteVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: version.DeleteVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete version method over HTTP. + + Args: + request (~.version.DeleteVersionRequest): + The request object. The request message for + [Versions.DeleteVersion][google.cloud.dialogflow.v2.Versions.DeleteVersion]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2/{name=projects/*/agent/versions/*}", + }, + { + "method": "delete", + "uri": "/v2/{name=projects/*/locations/*/agent/versions/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_version(request, metadata) + pb_request = version.DeleteVersionRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetVersion(VersionsRestStub): + def __hash__(self): + return hash("GetVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: version.GetVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> version.Version: + r"""Call the get version method over HTTP. + + Args: + request (~.version.GetVersionRequest): + The request object. The request message for + [Versions.GetVersion][google.cloud.dialogflow.v2.Versions.GetVersion]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.version.Version: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/agent/versions/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/agent/versions/*}", + }, + ] + request, metadata = self._interceptor.pre_get_version(request, metadata) + pb_request = version.GetVersionRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = version.Version() + pb_resp = version.Version.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_version(resp) + return resp + + class _ListVersions(VersionsRestStub): + def __hash__(self): + return hash("ListVersions") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: version.ListVersionsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> version.ListVersionsResponse: + r"""Call the list versions method over HTTP. + + Args: + request (~.version.ListVersionsRequest): + The request object. The request message for + [Versions.ListVersions][google.cloud.dialogflow.v2.Versions.ListVersions]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.version.ListVersionsResponse: + The response message for + [Versions.ListVersions][google.cloud.dialogflow.v2.Versions.ListVersions]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{parent=projects/*/agent}/versions", + }, + { + "method": "get", + "uri": "/v2/{parent=projects/*/locations/*/agent}/versions", + }, + ] + request, metadata = self._interceptor.pre_list_versions(request, metadata) + pb_request = version.ListVersionsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = version.ListVersionsResponse() + pb_resp = version.ListVersionsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_versions(resp) + return resp + + class _UpdateVersion(VersionsRestStub): + def __hash__(self): + return hash("UpdateVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_version.UpdateVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_version.Version: + r"""Call the update version method over HTTP. + + Args: + request (~.gcd_version.UpdateVersionRequest): + The request object. The request message for + [Versions.UpdateVersion][google.cloud.dialogflow.v2.Versions.UpdateVersion]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_version.Version: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2/{version.name=projects/*/agent/versions/*}", + "body": "version", + }, + { + "method": "patch", + "uri": "/v2/{version.name=projects/*/locations/*/agent/versions/*}", + "body": "version", + }, + ] + request, metadata = self._interceptor.pre_update_version(request, metadata) + pb_request = gcd_version.UpdateVersionRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_version.Version() + pb_resp = gcd_version.Version.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_version(resp) + return resp + + @property + def create_version( + self, + ) -> Callable[[gcd_version.CreateVersionRequest], gcd_version.Version]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_version( + self, + ) -> Callable[[version.DeleteVersionRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_version(self) -> Callable[[version.GetVersionRequest], version.Version]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_versions( + self, + ) -> Callable[[version.ListVersionsRequest], version.ListVersionsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListVersions(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_version( + self, + ) -> Callable[[gcd_version.UpdateVersionRequest], gcd_version.Version]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(VersionsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(VersionsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(VersionsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(VersionsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(VersionsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("VersionsRestTransport",) diff --git a/google/cloud/dialogflow_v2/types/agent.py b/google/cloud/dialogflow_v2/types/agent.py index e6cd85a35..e59ee97ee 100644 --- a/google/cloud/dialogflow_v2/types/agent.py +++ b/google/cloud/dialogflow_v2/types/agent.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/answer_record.py b/google/cloud/dialogflow_v2/types/answer_record.py index f8b9fd7b7..7a32d8302 100644 --- a/google/cloud/dialogflow_v2/types/answer_record.py +++ b/google/cloud/dialogflow_v2/types/answer_record.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/audio_config.py b/google/cloud/dialogflow_v2/types/audio_config.py index 704ff8b9a..7299f67b2 100644 --- a/google/cloud/dialogflow_v2/types/audio_config.py +++ b/google/cloud/dialogflow_v2/types/audio_config.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import duration_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/context.py b/google/cloud/dialogflow_v2/types/context.py index 767b9e3d2..98df11b01 100644 --- a/google/cloud/dialogflow_v2/types/context.py +++ b/google/cloud/dialogflow_v2/types/context.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/conversation.py b/google/cloud/dialogflow_v2/types/conversation.py index 6831167fe..b5dd0c6dc 100644 --- a/google/cloud/dialogflow_v2/types/conversation.py +++ b/google/cloud/dialogflow_v2/types/conversation.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import timestamp_pb2 # type: ignore @@ -430,6 +432,8 @@ class SuggestConversationSummaryRequest(proto.Message): Max number of messages prior to and including [latest_message] to use as context when compiling the suggestion. By default 500 and at most 1000. + assist_query_params (google.cloud.dialogflow_v2.types.AssistQueryParameters): + Parameters for a human assist query. """ conversation: str = proto.Field( @@ -444,6 +448,11 @@ class SuggestConversationSummaryRequest(proto.Message): proto.INT32, number=4, ) + assist_query_params: participant.AssistQueryParameters = proto.Field( + proto.MESSAGE, + number=5, + message=participant.AssistQueryParameters, + ) class SuggestConversationSummaryResponse(proto.Message): diff --git a/google/cloud/dialogflow_v2/types/conversation_dataset.py b/google/cloud/dialogflow_v2/types/conversation_dataset.py index e4515d247..78fb94010 100644 --- a/google/cloud/dialogflow_v2/types/conversation_dataset.py +++ b/google/cloud/dialogflow_v2/types/conversation_dataset.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import timestamp_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/conversation_event.py b/google/cloud/dialogflow_v2/types/conversation_event.py index d553db4dd..773d87fa7 100644 --- a/google/cloud/dialogflow_v2/types/conversation_event.py +++ b/google/cloud/dialogflow_v2/types/conversation_event.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.rpc import status_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/conversation_model.py b/google/cloud/dialogflow_v2/types/conversation_model.py index a1a3d6126..2a0f6d14d 100644 --- a/google/cloud/dialogflow_v2/types/conversation_model.py +++ b/google/cloud/dialogflow_v2/types/conversation_model.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import timestamp_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/conversation_profile.py b/google/cloud/dialogflow_v2/types/conversation_profile.py index 88d84b2b9..b2e759763 100644 --- a/google/cloud/dialogflow_v2/types/conversation_profile.py +++ b/google/cloud/dialogflow_v2/types/conversation_profile.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore @@ -100,6 +102,13 @@ class ConversationProfile(proto.Message): Name of the CX SecuritySettings reference for the agent. Format: ``projects//locations//securitySettings/``. + tts_config (google.cloud.dialogflow_v2.types.SynthesizeSpeechConfig): + Configuration for Text-to-Speech + synthesization. + Used by Phone Gateway to specify synthesization + options. If agent defines synthesization options + as well, agent settings overrides the option + here. """ name: str = proto.Field( @@ -167,6 +176,11 @@ class ConversationProfile(proto.Message): proto.STRING, number=13, ) + tts_config: audio_config.SynthesizeSpeechConfig = proto.Field( + proto.MESSAGE, + number=18, + message=audio_config.SynthesizeSpeechConfig, + ) class ListConversationProfilesRequest(proto.Message): diff --git a/google/cloud/dialogflow_v2/types/document.py b/google/cloud/dialogflow_v2/types/document.py index b6112fd8f..d727905a4 100644 --- a/google/cloud/dialogflow_v2/types/document.py +++ b/google/cloud/dialogflow_v2/types/document.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/entity_type.py b/google/cloud/dialogflow_v2/types/entity_type.py index 2e6d723e3..af86961a0 100644 --- a/google/cloud/dialogflow_v2/types/entity_type.py +++ b/google/cloud/dialogflow_v2/types/entity_type.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/environment.py b/google/cloud/dialogflow_v2/types/environment.py index 63c856a86..9e2928bce 100644 --- a/google/cloud/dialogflow_v2/types/environment.py +++ b/google/cloud/dialogflow_v2/types/environment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/fulfillment.py b/google/cloud/dialogflow_v2/types/fulfillment.py index 9f397663c..b246ab253 100644 --- a/google/cloud/dialogflow_v2/types/fulfillment.py +++ b/google/cloud/dialogflow_v2/types/fulfillment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/gcs.py b/google/cloud/dialogflow_v2/types/gcs.py index 477c8a873..d62b75e5f 100644 --- a/google/cloud/dialogflow_v2/types/gcs.py +++ b/google/cloud/dialogflow_v2/types/gcs.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflow_v2/types/human_agent_assistant_event.py b/google/cloud/dialogflow_v2/types/human_agent_assistant_event.py index 2698d2ec1..03b644a00 100644 --- a/google/cloud/dialogflow_v2/types/human_agent_assistant_event.py +++ b/google/cloud/dialogflow_v2/types/human_agent_assistant_event.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflow_v2/types/intent.py b/google/cloud/dialogflow_v2/types/intent.py index 416edbd5f..e0eb887ed 100644 --- a/google/cloud/dialogflow_v2/types/intent.py +++ b/google/cloud/dialogflow_v2/types/intent.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/knowledge_base.py b/google/cloud/dialogflow_v2/types/knowledge_base.py index 4bb252e35..87eee553e 100644 --- a/google/cloud/dialogflow_v2/types/knowledge_base.py +++ b/google/cloud/dialogflow_v2/types/knowledge_base.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/participant.py b/google/cloud/dialogflow_v2/types/participant.py index be37bb846..d56ed1cd7 100644 --- a/google/cloud/dialogflow_v2/types/participant.py +++ b/google/cloud/dialogflow_v2/types/participant.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/session.py b/google/cloud/dialogflow_v2/types/session.py index df31e528f..7d311be4a 100644 --- a/google/cloud/dialogflow_v2/types/session.py +++ b/google/cloud/dialogflow_v2/types/session.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import duration_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/session_entity_type.py b/google/cloud/dialogflow_v2/types/session_entity_type.py index f6aaa021d..4a6c45b61 100644 --- a/google/cloud/dialogflow_v2/types/session_entity_type.py +++ b/google/cloud/dialogflow_v2/types/session_entity_type.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/validation_result.py b/google/cloud/dialogflow_v2/types/validation_result.py index a7ef97838..16fbb942d 100644 --- a/google/cloud/dialogflow_v2/types/validation_result.py +++ b/google/cloud/dialogflow_v2/types/validation_result.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflow_v2/types/version.py b/google/cloud/dialogflow_v2/types/version.py index 9d6e97751..ca2be0cc7 100644 --- a/google/cloud/dialogflow_v2/types/version.py +++ b/google/cloud/dialogflow_v2/types/version.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2/types/webhook.py b/google/cloud/dialogflow_v2/types/webhook.py index 95675a378..7c0c7c3cd 100644 --- a/google/cloud/dialogflow_v2/types/webhook.py +++ b/google/cloud/dialogflow_v2/types/webhook.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import struct_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/gapic_metadata.json b/google/cloud/dialogflow_v2beta1/gapic_metadata.json index 19a5d2e0e..62c0128c9 100644 --- a/google/cloud/dialogflow_v2beta1/gapic_metadata.json +++ b/google/cloud/dialogflow_v2beta1/gapic_metadata.json @@ -106,6 +106,56 @@ ] } } + }, + "rest": { + "libraryClient": "AgentsClient", + "rpcs": { + "DeleteAgent": { + "methods": [ + "delete_agent" + ] + }, + "ExportAgent": { + "methods": [ + "export_agent" + ] + }, + "GetAgent": { + "methods": [ + "get_agent" + ] + }, + "GetValidationResult": { + "methods": [ + "get_validation_result" + ] + }, + "ImportAgent": { + "methods": [ + "import_agent" + ] + }, + "RestoreAgent": { + "methods": [ + "restore_agent" + ] + }, + "SearchAgents": { + "methods": [ + "search_agents" + ] + }, + "SetAgent": { + "methods": [ + "set_agent" + ] + }, + "TrainAgent": { + "methods": [ + "train_agent" + ] + } + } } } }, @@ -150,6 +200,26 @@ ] } } + }, + "rest": { + "libraryClient": "AnswerRecordsClient", + "rpcs": { + "GetAnswerRecord": { + "methods": [ + "get_answer_record" + ] + }, + "ListAnswerRecords": { + "methods": [ + "list_answer_records" + ] + }, + "UpdateAnswerRecord": { + "methods": [ + "update_answer_record" + ] + } + } } } }, @@ -224,6 +294,41 @@ ] } } + }, + "rest": { + "libraryClient": "ContextsClient", + "rpcs": { + "CreateContext": { + "methods": [ + "create_context" + ] + }, + "DeleteAllContexts": { + "methods": [ + "delete_all_contexts" + ] + }, + "DeleteContext": { + "methods": [ + "delete_context" + ] + }, + "GetContext": { + "methods": [ + "get_context" + ] + }, + "ListContexts": { + "methods": [ + "list_contexts" + ] + }, + "UpdateContext": { + "methods": [ + "update_context" + ] + } + } } } }, @@ -308,6 +413,46 @@ ] } } + }, + "rest": { + "libraryClient": "ConversationProfilesClient", + "rpcs": { + "ClearSuggestionFeatureConfig": { + "methods": [ + "clear_suggestion_feature_config" + ] + }, + "CreateConversationProfile": { + "methods": [ + "create_conversation_profile" + ] + }, + "DeleteConversationProfile": { + "methods": [ + "delete_conversation_profile" + ] + }, + "GetConversationProfile": { + "methods": [ + "get_conversation_profile" + ] + }, + "ListConversationProfiles": { + "methods": [ + "list_conversation_profiles" + ] + }, + "SetSuggestionFeatureConfig": { + "methods": [ + "set_suggestion_feature_config" + ] + }, + "UpdateConversationProfile": { + "methods": [ + "update_conversation_profile" + ] + } + } } } }, @@ -392,6 +537,46 @@ ] } } + }, + "rest": { + "libraryClient": "ConversationsClient", + "rpcs": { + "BatchCreateMessages": { + "methods": [ + "batch_create_messages" + ] + }, + "CompleteConversation": { + "methods": [ + "complete_conversation" + ] + }, + "CreateConversation": { + "methods": [ + "create_conversation" + ] + }, + "GetConversation": { + "methods": [ + "get_conversation" + ] + }, + "ListConversations": { + "methods": [ + "list_conversations" + ] + }, + "ListMessages": { + "methods": [ + "list_messages" + ] + }, + "SuggestConversationSummary": { + "methods": [ + "suggest_conversation_summary" + ] + } + } } } }, @@ -476,6 +661,46 @@ ] } } + }, + "rest": { + "libraryClient": "DocumentsClient", + "rpcs": { + "CreateDocument": { + "methods": [ + "create_document" + ] + }, + "DeleteDocument": { + "methods": [ + "delete_document" + ] + }, + "GetDocument": { + "methods": [ + "get_document" + ] + }, + "ImportDocuments": { + "methods": [ + "import_documents" + ] + }, + "ListDocuments": { + "methods": [ + "list_documents" + ] + }, + "ReloadDocument": { + "methods": [ + "reload_document" + ] + }, + "UpdateDocument": { + "methods": [ + "update_document" + ] + } + } } } }, @@ -536,8 +761,63 @@ } } }, - "grpc-async": { - "libraryClient": "EntityTypesAsyncClient", + "grpc-async": { + "libraryClient": "EntityTypesAsyncClient", + "rpcs": { + "BatchCreateEntities": { + "methods": [ + "batch_create_entities" + ] + }, + "BatchDeleteEntities": { + "methods": [ + "batch_delete_entities" + ] + }, + "BatchDeleteEntityTypes": { + "methods": [ + "batch_delete_entity_types" + ] + }, + "BatchUpdateEntities": { + "methods": [ + "batch_update_entities" + ] + }, + "BatchUpdateEntityTypes": { + "methods": [ + "batch_update_entity_types" + ] + }, + "CreateEntityType": { + "methods": [ + "create_entity_type" + ] + }, + "DeleteEntityType": { + "methods": [ + "delete_entity_type" + ] + }, + "GetEntityType": { + "methods": [ + "get_entity_type" + ] + }, + "ListEntityTypes": { + "methods": [ + "list_entity_types" + ] + }, + "UpdateEntityType": { + "methods": [ + "update_entity_type" + ] + } + } + }, + "rest": { + "libraryClient": "EntityTypesClient", "rpcs": { "BatchCreateEntities": { "methods": [ @@ -664,6 +944,41 @@ ] } } + }, + "rest": { + "libraryClient": "EnvironmentsClient", + "rpcs": { + "CreateEnvironment": { + "methods": [ + "create_environment" + ] + }, + "DeleteEnvironment": { + "methods": [ + "delete_environment" + ] + }, + "GetEnvironment": { + "methods": [ + "get_environment" + ] + }, + "GetEnvironmentHistory": { + "methods": [ + "get_environment_history" + ] + }, + "ListEnvironments": { + "methods": [ + "list_environments" + ] + }, + "UpdateEnvironment": { + "methods": [ + "update_environment" + ] + } + } } } }, @@ -698,6 +1013,21 @@ ] } } + }, + "rest": { + "libraryClient": "FulfillmentsClient", + "rpcs": { + "GetFulfillment": { + "methods": [ + "get_fulfillment" + ] + }, + "UpdateFulfillment": { + "methods": [ + "update_fulfillment" + ] + } + } } } }, @@ -782,6 +1112,46 @@ ] } } + }, + "rest": { + "libraryClient": "IntentsClient", + "rpcs": { + "BatchDeleteIntents": { + "methods": [ + "batch_delete_intents" + ] + }, + "BatchUpdateIntents": { + "methods": [ + "batch_update_intents" + ] + }, + "CreateIntent": { + "methods": [ + "create_intent" + ] + }, + "DeleteIntent": { + "methods": [ + "delete_intent" + ] + }, + "GetIntent": { + "methods": [ + "get_intent" + ] + }, + "ListIntents": { + "methods": [ + "list_intents" + ] + }, + "UpdateIntent": { + "methods": [ + "update_intent" + ] + } + } } } }, @@ -846,6 +1216,36 @@ ] } } + }, + "rest": { + "libraryClient": "KnowledgeBasesClient", + "rpcs": { + "CreateKnowledgeBase": { + "methods": [ + "create_knowledge_base" + ] + }, + "DeleteKnowledgeBase": { + "methods": [ + "delete_knowledge_base" + ] + }, + "GetKnowledgeBase": { + "methods": [ + "get_knowledge_base" + ] + }, + "ListKnowledgeBases": { + "methods": [ + "list_knowledge_bases" + ] + }, + "UpdateKnowledgeBase": { + "methods": [ + "update_knowledge_base" + ] + } + } } } }, @@ -970,6 +1370,66 @@ ] } } + }, + "rest": { + "libraryClient": "ParticipantsClient", + "rpcs": { + "AnalyzeContent": { + "methods": [ + "analyze_content" + ] + }, + "CompileSuggestion": { + "methods": [ + "compile_suggestion" + ] + }, + "CreateParticipant": { + "methods": [ + "create_participant" + ] + }, + "GetParticipant": { + "methods": [ + "get_participant" + ] + }, + "ListParticipants": { + "methods": [ + "list_participants" + ] + }, + "ListSuggestions": { + "methods": [ + "list_suggestions" + ] + }, + "StreamingAnalyzeContent": { + "methods": [ + "streaming_analyze_content" + ] + }, + "SuggestArticles": { + "methods": [ + "suggest_articles" + ] + }, + "SuggestFaqAnswers": { + "methods": [ + "suggest_faq_answers" + ] + }, + "SuggestSmartReplies": { + "methods": [ + "suggest_smart_replies" + ] + }, + "UpdateParticipant": { + "methods": [ + "update_participant" + ] + } + } } } }, @@ -1034,6 +1494,36 @@ ] } } + }, + "rest": { + "libraryClient": "SessionEntityTypesClient", + "rpcs": { + "CreateSessionEntityType": { + "methods": [ + "create_session_entity_type" + ] + }, + "DeleteSessionEntityType": { + "methods": [ + "delete_session_entity_type" + ] + }, + "GetSessionEntityType": { + "methods": [ + "get_session_entity_type" + ] + }, + "ListSessionEntityTypes": { + "methods": [ + "list_session_entity_types" + ] + }, + "UpdateSessionEntityType": { + "methods": [ + "update_session_entity_type" + ] + } + } } } }, @@ -1068,6 +1558,21 @@ ] } } + }, + "rest": { + "libraryClient": "SessionsClient", + "rpcs": { + "DetectIntent": { + "methods": [ + "detect_intent" + ] + }, + "StreamingDetectIntent": { + "methods": [ + "streaming_detect_intent" + ] + } + } } } }, @@ -1132,6 +1637,36 @@ ] } } + }, + "rest": { + "libraryClient": "VersionsClient", + "rpcs": { + "CreateVersion": { + "methods": [ + "create_version" + ] + }, + "DeleteVersion": { + "methods": [ + "delete_version" + ] + }, + "GetVersion": { + "methods": [ + "get_version" + ] + }, + "ListVersions": { + "methods": [ + "list_versions" + ] + }, + "UpdateVersion": { + "methods": [ + "update_version" + ] + } + } } } } diff --git a/google/cloud/dialogflow_v2beta1/services/agents/client.py b/google/cloud/dialogflow_v2beta1/services/agents/client.py index 91ecdf50f..60d1ec57f 100644 --- a/google/cloud/dialogflow_v2beta1/services/agents/client.py +++ b/google/cloud/dialogflow_v2beta1/services/agents/client.py @@ -61,6 +61,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, AgentsTransport from .transports.grpc import AgentsGrpcTransport from .transports.grpc_asyncio import AgentsGrpcAsyncIOTransport +from .transports.rest import AgentsRestTransport class AgentsClientMeta(type): @@ -74,6 +75,7 @@ class AgentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[AgentsTransport]] _transport_registry["grpc"] = AgentsGrpcTransport _transport_registry["grpc_asyncio"] = AgentsGrpcAsyncIOTransport + _transport_registry["rest"] = AgentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/agents/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/agents/transports/__init__.py index fa8faf8d6..38b6ef776 100644 --- a/google/cloud/dialogflow_v2beta1/services/agents/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/agents/transports/__init__.py @@ -19,14 +19,18 @@ from .base import AgentsTransport from .grpc import AgentsGrpcTransport from .grpc_asyncio import AgentsGrpcAsyncIOTransport +from .rest import AgentsRestInterceptor, AgentsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[AgentsTransport]] _transport_registry["grpc"] = AgentsGrpcTransport _transport_registry["grpc_asyncio"] = AgentsGrpcAsyncIOTransport +_transport_registry["rest"] = AgentsRestTransport __all__ = ( "AgentsTransport", "AgentsGrpcTransport", "AgentsGrpcAsyncIOTransport", + "AgentsRestTransport", + "AgentsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/agents/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/agents/transports/rest.py new file mode 100644 index 000000000..200ff770e --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/agents/transports/rest.py @@ -0,0 +1,1918 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2beta1.types import agent +from google.cloud.dialogflow_v2beta1.types import agent as gcd_agent +from google.cloud.dialogflow_v2beta1.types import validation_result + +from .base import AgentsTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class AgentsRestInterceptor: + """Interceptor for Agents. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the AgentsRestTransport. + + .. code-block:: python + class MyCustomAgentsInterceptor(AgentsRestInterceptor): + def pre_delete_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_export_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_export_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_validation_result(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_validation_result(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_import_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_import_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_restore_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_restore_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_search_agents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_search_agents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_set_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_set_agent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_train_agent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_train_agent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = AgentsRestTransport(interceptor=MyCustomAgentsInterceptor()) + client = AgentsClient(transport=transport) + + + """ + + def pre_delete_agent( + self, request: agent.DeleteAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.DeleteAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def pre_export_agent( + self, request: agent.ExportAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.ExportAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for export_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_export_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for export_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_agent( + self, request: agent.GetAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.GetAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_agent(self, response: agent.Agent) -> agent.Agent: + """Post-rpc interceptor for get_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_validation_result( + self, + request: agent.GetValidationResultRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[agent.GetValidationResultRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_validation_result + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_validation_result( + self, response: validation_result.ValidationResult + ) -> validation_result.ValidationResult: + """Post-rpc interceptor for get_validation_result + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_import_agent( + self, request: agent.ImportAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.ImportAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for import_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_import_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for import_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_restore_agent( + self, request: agent.RestoreAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.RestoreAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for restore_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_restore_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for restore_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_search_agents( + self, request: agent.SearchAgentsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.SearchAgentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for search_agents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_search_agents( + self, response: agent.SearchAgentsResponse + ) -> agent.SearchAgentsResponse: + """Post-rpc interceptor for search_agents + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_set_agent( + self, request: gcd_agent.SetAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[gcd_agent.SetAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for set_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_set_agent(self, response: gcd_agent.Agent) -> gcd_agent.Agent: + """Post-rpc interceptor for set_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_train_agent( + self, request: agent.TrainAgentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[agent.TrainAgentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for train_agent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_train_agent( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for train_agent + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Agents server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Agents server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class AgentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: AgentsRestInterceptor + + +class AgentsRestTransport(AgentsTransport): + """REST backend transport for Agents. + + Service for managing + [Agents][google.cloud.dialogflow.v2beta1.Agent]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[AgentsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or AgentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2beta1", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _DeleteAgent(AgentsRestStub): + def __hash__(self): + return hash("DeleteAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.DeleteAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete agent method over HTTP. + + Args: + request (~.agent.DeleteAgentRequest): + The request object. The request message for + [Agents.DeleteAgent][google.cloud.dialogflow.v2beta1.Agents.DeleteAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2beta1/{parent=projects/*}/agent", + }, + { + "method": "delete", + "uri": "/v2beta1/{parent=projects/*/locations/*}/agent", + }, + ] + request, metadata = self._interceptor.pre_delete_agent(request, metadata) + pb_request = agent.DeleteAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _ExportAgent(AgentsRestStub): + def __hash__(self): + return hash("ExportAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.ExportAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the export agent method over HTTP. + + Args: + request (~.agent.ExportAgentRequest): + The request object. The request message for + [Agents.ExportAgent][google.cloud.dialogflow.v2beta1.Agents.ExportAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*}/agent:export", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*}/agent:export", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_export_agent(request, metadata) + pb_request = agent.ExportAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_export_agent(resp) + return resp + + class _GetAgent(AgentsRestStub): + def __hash__(self): + return hash("GetAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.GetAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.Agent: + r"""Call the get agent method over HTTP. + + Args: + request (~.agent.GetAgentRequest): + The request object. The request message for + [Agents.GetAgent][google.cloud.dialogflow.v2beta1.Agents.GetAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.agent.Agent: + A Dialogflow agent is a virtual agent that handles + conversations with your end-users. It is a natural + language understanding module that understands the + nuances of human language. Dialogflow translates + end-user text or audio during a conversation to + structured data that your apps and services can + understand. You design and build a Dialogflow agent to + handle the types of conversations required for your + system. + + For more information about agents, see the `Agent + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*}/agent", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*}/agent", + }, + ] + request, metadata = self._interceptor.pre_get_agent(request, metadata) + pb_request = agent.GetAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = agent.Agent() + pb_resp = agent.Agent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_agent(resp) + return resp + + class _GetValidationResult(AgentsRestStub): + def __hash__(self): + return hash("GetValidationResult") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.GetValidationResultRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> validation_result.ValidationResult: + r"""Call the get validation result method over HTTP. + + Args: + request (~.agent.GetValidationResultRequest): + The request object. The request message for + [Agents.GetValidationResult][google.cloud.dialogflow.v2beta1.Agents.GetValidationResult]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.validation_result.ValidationResult: + Represents the output of agent + validation. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*}/agent/validationResult", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*}/agent/validationResult", + }, + ] + request, metadata = self._interceptor.pre_get_validation_result( + request, metadata + ) + pb_request = agent.GetValidationResultRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = validation_result.ValidationResult() + pb_resp = validation_result.ValidationResult.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_validation_result(resp) + return resp + + class _ImportAgent(AgentsRestStub): + def __hash__(self): + return hash("ImportAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.ImportAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the import agent method over HTTP. + + Args: + request (~.agent.ImportAgentRequest): + The request object. The request message for + [Agents.ImportAgent][google.cloud.dialogflow.v2beta1.Agents.ImportAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*}/agent:import", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*}/agent:import", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_import_agent(request, metadata) + pb_request = agent.ImportAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_import_agent(resp) + return resp + + class _RestoreAgent(AgentsRestStub): + def __hash__(self): + return hash("RestoreAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.RestoreAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the restore agent method over HTTP. + + Args: + request (~.agent.RestoreAgentRequest): + The request object. The request message for + [Agents.RestoreAgent][google.cloud.dialogflow.v2beta1.Agents.RestoreAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*}/agent:restore", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*}/agent:restore", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_restore_agent(request, metadata) + pb_request = agent.RestoreAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_restore_agent(resp) + return resp + + class _SearchAgents(AgentsRestStub): + def __hash__(self): + return hash("SearchAgents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.SearchAgentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.SearchAgentsResponse: + r"""Call the search agents method over HTTP. + + Args: + request (~.agent.SearchAgentsRequest): + The request object. The request message for + [Agents.SearchAgents][google.cloud.dialogflow.v2beta1.Agents.SearchAgents]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.agent.SearchAgentsResponse: + The response message for + [Agents.SearchAgents][google.cloud.dialogflow.v2beta1.Agents.SearchAgents]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*}/agent:search", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*}/agent:search", + }, + ] + request, metadata = self._interceptor.pre_search_agents(request, metadata) + pb_request = agent.SearchAgentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = agent.SearchAgentsResponse() + pb_resp = agent.SearchAgentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_search_agents(resp) + return resp + + class _SetAgent(AgentsRestStub): + def __hash__(self): + return hash("SetAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_agent.SetAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_agent.Agent: + r"""Call the set agent method over HTTP. + + Args: + request (~.gcd_agent.SetAgentRequest): + The request object. The request message for + [Agents.SetAgent][google.cloud.dialogflow.v2beta1.Agents.SetAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_agent.Agent: + A Dialogflow agent is a virtual agent that handles + conversations with your end-users. It is a natural + language understanding module that understands the + nuances of human language. Dialogflow translates + end-user text or audio during a conversation to + structured data that your apps and services can + understand. You design and build a Dialogflow agent to + handle the types of conversations required for your + system. + + For more information about agents, see the `Agent + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{agent.parent=projects/*}/agent", + "body": "agent", + }, + { + "method": "post", + "uri": "/v2beta1/{agent.parent=projects/*/locations/*}/agent", + "body": "agent", + }, + ] + request, metadata = self._interceptor.pre_set_agent(request, metadata) + pb_request = gcd_agent.SetAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_agent.Agent() + pb_resp = gcd_agent.Agent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_set_agent(resp) + return resp + + class _TrainAgent(AgentsRestStub): + def __hash__(self): + return hash("TrainAgent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: agent.TrainAgentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the train agent method over HTTP. + + Args: + request (~.agent.TrainAgentRequest): + The request object. The request message for + [Agents.TrainAgent][google.cloud.dialogflow.v2beta1.Agents.TrainAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*}/agent:train", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*}/agent:train", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_train_agent(request, metadata) + pb_request = agent.TrainAgentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_train_agent(resp) + return resp + + @property + def delete_agent(self) -> Callable[[agent.DeleteAgentRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def export_agent( + self, + ) -> Callable[[agent.ExportAgentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ExportAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_agent(self) -> Callable[[agent.GetAgentRequest], agent.Agent]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_validation_result( + self, + ) -> Callable[ + [agent.GetValidationResultRequest], validation_result.ValidationResult + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetValidationResult(self._session, self._host, self._interceptor) # type: ignore + + @property + def import_agent( + self, + ) -> Callable[[agent.ImportAgentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ImportAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def restore_agent( + self, + ) -> Callable[[agent.RestoreAgentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._RestoreAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def search_agents( + self, + ) -> Callable[[agent.SearchAgentsRequest], agent.SearchAgentsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SearchAgents(self._session, self._host, self._interceptor) # type: ignore + + @property + def set_agent(self) -> Callable[[gcd_agent.SetAgentRequest], gcd_agent.Agent]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SetAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def train_agent( + self, + ) -> Callable[[agent.TrainAgentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._TrainAgent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(AgentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(AgentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(AgentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(AgentsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(AgentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("AgentsRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/answer_records/client.py b/google/cloud/dialogflow_v2beta1/services/answer_records/client.py index ca5019b0a..504d037f0 100644 --- a/google/cloud/dialogflow_v2beta1/services/answer_records/client.py +++ b/google/cloud/dialogflow_v2beta1/services/answer_records/client.py @@ -58,6 +58,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, AnswerRecordsTransport from .transports.grpc import AnswerRecordsGrpcTransport from .transports.grpc_asyncio import AnswerRecordsGrpcAsyncIOTransport +from .transports.rest import AnswerRecordsRestTransport class AnswerRecordsClientMeta(type): @@ -71,6 +72,7 @@ class AnswerRecordsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[AnswerRecordsTransport]] _transport_registry["grpc"] = AnswerRecordsGrpcTransport _transport_registry["grpc_asyncio"] = AnswerRecordsGrpcAsyncIOTransport + _transport_registry["rest"] = AnswerRecordsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/answer_records/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/answer_records/transports/__init__.py index 08caa497a..3b2af894e 100644 --- a/google/cloud/dialogflow_v2beta1/services/answer_records/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/answer_records/transports/__init__.py @@ -19,14 +19,18 @@ from .base import AnswerRecordsTransport from .grpc import AnswerRecordsGrpcTransport from .grpc_asyncio import AnswerRecordsGrpcAsyncIOTransport +from .rest import AnswerRecordsRestInterceptor, AnswerRecordsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[AnswerRecordsTransport]] _transport_registry["grpc"] = AnswerRecordsGrpcTransport _transport_registry["grpc_asyncio"] = AnswerRecordsGrpcAsyncIOTransport +_transport_registry["rest"] = AnswerRecordsRestTransport __all__ = ( "AnswerRecordsTransport", "AnswerRecordsGrpcTransport", "AnswerRecordsGrpcAsyncIOTransport", + "AnswerRecordsRestTransport", + "AnswerRecordsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/answer_records/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/answer_records/transports/rest.py new file mode 100644 index 000000000..4056eb6ba --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/answer_records/transports/rest.py @@ -0,0 +1,1093 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.dialogflow_v2beta1.types import answer_record as gcd_answer_record +from google.cloud.dialogflow_v2beta1.types import answer_record + +from .base import AnswerRecordsTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class AnswerRecordsRestInterceptor: + """Interceptor for AnswerRecords. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the AnswerRecordsRestTransport. + + .. code-block:: python + class MyCustomAnswerRecordsInterceptor(AnswerRecordsRestInterceptor): + def pre_get_answer_record(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_answer_record(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_answer_records(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_answer_records(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_answer_record(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_answer_record(self, response): + logging.log(f"Received response: {response}") + return response + + transport = AnswerRecordsRestTransport(interceptor=MyCustomAnswerRecordsInterceptor()) + client = AnswerRecordsClient(transport=transport) + + + """ + + def pre_get_answer_record( + self, + request: answer_record.GetAnswerRecordRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[answer_record.GetAnswerRecordRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_answer_record + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_get_answer_record( + self, response: answer_record.AnswerRecord + ) -> answer_record.AnswerRecord: + """Post-rpc interceptor for get_answer_record + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_list_answer_records( + self, + request: answer_record.ListAnswerRecordsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[answer_record.ListAnswerRecordsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_answer_records + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_list_answer_records( + self, response: answer_record.ListAnswerRecordsResponse + ) -> answer_record.ListAnswerRecordsResponse: + """Post-rpc interceptor for list_answer_records + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_update_answer_record( + self, + request: gcd_answer_record.UpdateAnswerRecordRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_answer_record.UpdateAnswerRecordRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_answer_record + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_update_answer_record( + self, response: gcd_answer_record.AnswerRecord + ) -> gcd_answer_record.AnswerRecord: + """Post-rpc interceptor for update_answer_record + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the AnswerRecords server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the AnswerRecords server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class AnswerRecordsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: AnswerRecordsRestInterceptor + + +class AnswerRecordsRestTransport(AnswerRecordsTransport): + """REST backend transport for AnswerRecords. + + Service for managing + [AnswerRecords][google.cloud.dialogflow.v2beta1.AnswerRecord]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[AnswerRecordsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or AnswerRecordsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _GetAnswerRecord(AnswerRecordsRestStub): + def __hash__(self): + return hash("GetAnswerRecord") + + def __call__( + self, + request: answer_record.GetAnswerRecordRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> answer_record.AnswerRecord: + r"""Call the get answer record method over HTTP. + + Args: + request (~.answer_record.GetAnswerRecordRequest): + The request object. Request message for + [AnswerRecords.GetAnswerRecord][google.cloud.dialogflow.v2beta1.AnswerRecords.GetAnswerRecord]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.answer_record.AnswerRecord: + Answer records are records to manage answer history and + feedbacks for Dialogflow. + + Currently, answer record includes: + + - human agent assistant article suggestion + - human agent assistant faq article + + It doesn't include: + + - ``DetectIntent`` intent matching + - ``DetectIntent`` knowledge + + Answer records are not related to the conversation + history in the Dialogflow Console. A Record is generated + even when the end-user disables conversation history in + the console. Records are created when there's a human + agent assistant suggestion generated. + + A typical workflow for customers provide feedback to an + answer is: + + 1. For human agent assistant, customers get suggestion + via ListSuggestions API. Together with the answers, + [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] + are returned to the customers. + 2. The customer uses the + [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] + to call the [UpdateAnswerRecord][] method to send + feedback about a specific answer that they believe is + wrong. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/answerRecords/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/answerRecords/*}", + }, + ] + request, metadata = self._interceptor.pre_get_answer_record( + request, metadata + ) + pb_request = answer_record.GetAnswerRecordRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = answer_record.AnswerRecord() + pb_resp = answer_record.AnswerRecord.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_answer_record(resp) + return resp + + class _ListAnswerRecords(AnswerRecordsRestStub): + def __hash__(self): + return hash("ListAnswerRecords") + + def __call__( + self, + request: answer_record.ListAnswerRecordsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> answer_record.ListAnswerRecordsResponse: + r"""Call the list answer records method over HTTP. + + Args: + request (~.answer_record.ListAnswerRecordsRequest): + The request object. Request message for + [AnswerRecords.ListAnswerRecords][google.cloud.dialogflow.v2beta1.AnswerRecords.ListAnswerRecords]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.answer_record.ListAnswerRecordsResponse: + Response message for + [AnswerRecords.ListAnswerRecords][google.cloud.dialogflow.v2beta1.AnswerRecords.ListAnswerRecords]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*}/answerRecords", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*}/answerRecords", + }, + ] + request, metadata = self._interceptor.pre_list_answer_records( + request, metadata + ) + pb_request = answer_record.ListAnswerRecordsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = answer_record.ListAnswerRecordsResponse() + pb_resp = answer_record.ListAnswerRecordsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_answer_records(resp) + return resp + + class _UpdateAnswerRecord(AnswerRecordsRestStub): + def __hash__(self): + return hash("UpdateAnswerRecord") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_answer_record.UpdateAnswerRecordRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_answer_record.AnswerRecord: + r"""Call the update answer record method over HTTP. + + Args: + request (~.gcd_answer_record.UpdateAnswerRecordRequest): + The request object. Request message for + [AnswerRecords.UpdateAnswerRecord][google.cloud.dialogflow.v2beta1.AnswerRecords.UpdateAnswerRecord]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_answer_record.AnswerRecord: + Answer records are records to manage answer history and + feedbacks for Dialogflow. + + Currently, answer record includes: + + - human agent assistant article suggestion + - human agent assistant faq article + + It doesn't include: + + - ``DetectIntent`` intent matching + - ``DetectIntent`` knowledge + + Answer records are not related to the conversation + history in the Dialogflow Console. A Record is generated + even when the end-user disables conversation history in + the console. Records are created when there's a human + agent assistant suggestion generated. + + A typical workflow for customers provide feedback to an + answer is: + + 1. For human agent assistant, customers get suggestion + via ListSuggestions API. Together with the answers, + [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] + are returned to the customers. + 2. The customer uses the + [AnswerRecord.name][google.cloud.dialogflow.v2beta1.AnswerRecord.name] + to call the [UpdateAnswerRecord][] method to send + feedback about a specific answer that they believe is + wrong. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{answer_record.name=projects/*/answerRecords/*}", + "body": "answer_record", + }, + { + "method": "patch", + "uri": "/v2beta1/{answer_record.name=projects/*/locations/*/answerRecords/*}", + "body": "answer_record", + }, + ] + request, metadata = self._interceptor.pre_update_answer_record( + request, metadata + ) + pb_request = gcd_answer_record.UpdateAnswerRecordRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_answer_record.AnswerRecord() + pb_resp = gcd_answer_record.AnswerRecord.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_answer_record(resp) + return resp + + @property + def get_answer_record( + self, + ) -> Callable[[answer_record.GetAnswerRecordRequest], answer_record.AnswerRecord]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetAnswerRecord(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_answer_records( + self, + ) -> Callable[ + [answer_record.ListAnswerRecordsRequest], + answer_record.ListAnswerRecordsResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListAnswerRecords(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_answer_record( + self, + ) -> Callable[ + [gcd_answer_record.UpdateAnswerRecordRequest], gcd_answer_record.AnswerRecord + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateAnswerRecord(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(AnswerRecordsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(AnswerRecordsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(AnswerRecordsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(AnswerRecordsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(AnswerRecordsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("AnswerRecordsRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/contexts/client.py b/google/cloud/dialogflow_v2beta1/services/contexts/client.py index f6ab75791..9cfb6334c 100644 --- a/google/cloud/dialogflow_v2beta1/services/contexts/client.py +++ b/google/cloud/dialogflow_v2beta1/services/contexts/client.py @@ -58,6 +58,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, ContextsTransport from .transports.grpc import ContextsGrpcTransport from .transports.grpc_asyncio import ContextsGrpcAsyncIOTransport +from .transports.rest import ContextsRestTransport class ContextsClientMeta(type): @@ -71,6 +72,7 @@ class ContextsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[ContextsTransport]] _transport_registry["grpc"] = ContextsGrpcTransport _transport_registry["grpc_asyncio"] = ContextsGrpcAsyncIOTransport + _transport_registry["rest"] = ContextsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/contexts/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/contexts/transports/__init__.py index decaf2fd8..2bb76253d 100644 --- a/google/cloud/dialogflow_v2beta1/services/contexts/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/contexts/transports/__init__.py @@ -19,14 +19,18 @@ from .base import ContextsTransport from .grpc import ContextsGrpcTransport from .grpc_asyncio import ContextsGrpcAsyncIOTransport +from .rest import ContextsRestInterceptor, ContextsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[ContextsTransport]] _transport_registry["grpc"] = ContextsGrpcTransport _transport_registry["grpc_asyncio"] = ContextsGrpcAsyncIOTransport +_transport_registry["rest"] = ContextsRestTransport __all__ = ( "ContextsTransport", "ContextsGrpcTransport", "ContextsGrpcAsyncIOTransport", + "ContextsRestTransport", + "ContextsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/contexts/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/contexts/transports/rest.py new file mode 100644 index 000000000..f3d21503e --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/contexts/transports/rest.py @@ -0,0 +1,1490 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2beta1.types import context +from google.cloud.dialogflow_v2beta1.types import context as gcd_context + +from .base import ContextsTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class ContextsRestInterceptor: + """Interceptor for Contexts. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the ContextsRestTransport. + + .. code-block:: python + class MyCustomContextsInterceptor(ContextsRestInterceptor): + def pre_create_context(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_context(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_all_contexts(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_delete_context(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_context(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_context(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_contexts(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_contexts(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_context(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_context(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ContextsRestTransport(interceptor=MyCustomContextsInterceptor()) + client = ContextsClient(transport=transport) + + + """ + + def pre_create_context( + self, + request: gcd_context.CreateContextRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_context.CreateContextRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_context + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_create_context(self, response: gcd_context.Context) -> gcd_context.Context: + """Post-rpc interceptor for create_context + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_delete_all_contexts( + self, + request: context.DeleteAllContextsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[context.DeleteAllContextsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_all_contexts + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def pre_delete_context( + self, request: context.DeleteContextRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[context.DeleteContextRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_context + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def pre_get_context( + self, request: context.GetContextRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[context.GetContextRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_context + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_get_context(self, response: context.Context) -> context.Context: + """Post-rpc interceptor for get_context + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_list_contexts( + self, request: context.ListContextsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[context.ListContextsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_contexts + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_list_contexts( + self, response: context.ListContextsResponse + ) -> context.ListContextsResponse: + """Post-rpc interceptor for list_contexts + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_update_context( + self, + request: gcd_context.UpdateContextRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_context.UpdateContextRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_context + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_update_context(self, response: gcd_context.Context) -> gcd_context.Context: + """Post-rpc interceptor for update_context + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Contexts server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Contexts server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ContextsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ContextsRestInterceptor + + +class ContextsRestTransport(ContextsTransport): + """REST backend transport for Contexts. + + Service for managing + [Contexts][google.cloud.dialogflow.v2beta1.Context]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[ContextsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or ContextsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateContext(ContextsRestStub): + def __hash__(self): + return hash("CreateContext") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_context.CreateContextRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_context.Context: + r"""Call the create context method over HTTP. + + Args: + request (~.gcd_context.CreateContextRequest): + The request object. The request message for + [Contexts.CreateContext][google.cloud.dialogflow.v2beta1.Contexts.CreateContext]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_context.Context: + Dialogflow contexts are similar to natural language + context. If a person says to you "they are orange", you + need context in order to understand what "they" is + referring to. Similarly, for Dialogflow to handle an + end-user expression like that, it needs to be provided + with context in order to correctly match an intent. + + Using contexts, you can control the flow of a + conversation. You can configure contexts for an intent + by setting input and output contexts, which are + identified by string names. When an intent is matched, + any configured output contexts for that intent become + active. While any contexts are active, Dialogflow is + more likely to match intents that are configured with + input contexts that correspond to the currently active + contexts. + + For more information about context, see the `Contexts + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent/sessions/*}/contexts", + "body": "context", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent/environments/*/users/*/sessions/*}/contexts", + "body": "context", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/sessions/*}/contexts", + "body": "context", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/environments/*/users/*/sessions/*}/contexts", + "body": "context", + }, + ] + request, metadata = self._interceptor.pre_create_context(request, metadata) + pb_request = gcd_context.CreateContextRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_context.Context() + pb_resp = gcd_context.Context.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_context(resp) + return resp + + class _DeleteAllContexts(ContextsRestStub): + def __hash__(self): + return hash("DeleteAllContexts") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: context.DeleteAllContextsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete all contexts method over HTTP. + + Args: + request (~.context.DeleteAllContextsRequest): + The request object. The request message for + [Contexts.DeleteAllContexts][google.cloud.dialogflow.v2beta1.Contexts.DeleteAllContexts]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2beta1/{parent=projects/*/agent/sessions/*}/contexts", + }, + { + "method": "delete", + "uri": "/v2beta1/{parent=projects/*/agent/environments/*/users/*/sessions/*}/contexts", + }, + { + "method": "delete", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/sessions/*}/contexts", + }, + { + "method": "delete", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/environments/*/users/*/sessions/*}/contexts", + }, + ] + request, metadata = self._interceptor.pre_delete_all_contexts( + request, metadata + ) + pb_request = context.DeleteAllContextsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _DeleteContext(ContextsRestStub): + def __hash__(self): + return hash("DeleteContext") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: context.DeleteContextRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete context method over HTTP. + + Args: + request (~.context.DeleteContextRequest): + The request object. The request message for + [Contexts.DeleteContext][google.cloud.dialogflow.v2beta1.Contexts.DeleteContext]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/agent/sessions/*/contexts/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/agent/environments/*/users/*/sessions/*/contexts/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/sessions/*/contexts/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/contexts/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_context(request, metadata) + pb_request = context.DeleteContextRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetContext(ContextsRestStub): + def __hash__(self): + return hash("GetContext") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: context.GetContextRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> context.Context: + r"""Call the get context method over HTTP. + + Args: + request (~.context.GetContextRequest): + The request object. The request message for + [Contexts.GetContext][google.cloud.dialogflow.v2beta1.Contexts.GetContext]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.context.Context: + Dialogflow contexts are similar to natural language + context. If a person says to you "they are orange", you + need context in order to understand what "they" is + referring to. Similarly, for Dialogflow to handle an + end-user expression like that, it needs to be provided + with context in order to correctly match an intent. + + Using contexts, you can control the flow of a + conversation. You can configure contexts for an intent + by setting input and output contexts, which are + identified by string names. When an intent is matched, + any configured output contexts for that intent become + active. While any contexts are active, Dialogflow is + more likely to match intents that are configured with + input contexts that correspond to the currently active + contexts. + + For more information about context, see the `Contexts + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/agent/sessions/*/contexts/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/agent/environments/*/users/*/sessions/*/contexts/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/sessions/*/contexts/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/contexts/*}", + }, + ] + request, metadata = self._interceptor.pre_get_context(request, metadata) + pb_request = context.GetContextRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = context.Context() + pb_resp = context.Context.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_context(resp) + return resp + + class _ListContexts(ContextsRestStub): + def __hash__(self): + return hash("ListContexts") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: context.ListContextsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> context.ListContextsResponse: + r"""Call the list contexts method over HTTP. + + Args: + request (~.context.ListContextsRequest): + The request object. The request message for + [Contexts.ListContexts][google.cloud.dialogflow.v2beta1.Contexts.ListContexts]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.context.ListContextsResponse: + The response message for + [Contexts.ListContexts][google.cloud.dialogflow.v2beta1.Contexts.ListContexts]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent/sessions/*}/contexts", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent/environments/*/users/*/sessions/*}/contexts", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/sessions/*}/contexts", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/environments/*/users/*/sessions/*}/contexts", + }, + ] + request, metadata = self._interceptor.pre_list_contexts(request, metadata) + pb_request = context.ListContextsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = context.ListContextsResponse() + pb_resp = context.ListContextsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_contexts(resp) + return resp + + class _UpdateContext(ContextsRestStub): + def __hash__(self): + return hash("UpdateContext") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_context.UpdateContextRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_context.Context: + r"""Call the update context method over HTTP. + + Args: + request (~.gcd_context.UpdateContextRequest): + The request object. The request message for + [Contexts.UpdateContext][google.cloud.dialogflow.v2beta1.Contexts.UpdateContext]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_context.Context: + Dialogflow contexts are similar to natural language + context. If a person says to you "they are orange", you + need context in order to understand what "they" is + referring to. Similarly, for Dialogflow to handle an + end-user expression like that, it needs to be provided + with context in order to correctly match an intent. + + Using contexts, you can control the flow of a + conversation. You can configure contexts for an intent + by setting input and output contexts, which are + identified by string names. When an intent is matched, + any configured output contexts for that intent become + active. While any contexts are active, Dialogflow is + more likely to match intents that are configured with + input contexts that correspond to the currently active + contexts. + + For more information about context, see the `Contexts + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{context.name=projects/*/agent/sessions/*/contexts/*}", + "body": "context", + }, + { + "method": "patch", + "uri": "/v2beta1/{context.name=projects/*/agent/environments/*/users/*/sessions/*/contexts/*}", + "body": "context", + }, + { + "method": "patch", + "uri": "/v2beta1/{context.name=projects/*/locations/*/agent/sessions/*/contexts/*}", + "body": "context", + }, + { + "method": "patch", + "uri": "/v2beta1/{context.name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/contexts/*}", + "body": "context", + }, + ] + request, metadata = self._interceptor.pre_update_context(request, metadata) + pb_request = gcd_context.UpdateContextRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_context.Context() + pb_resp = gcd_context.Context.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_context(resp) + return resp + + @property + def create_context( + self, + ) -> Callable[[gcd_context.CreateContextRequest], gcd_context.Context]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateContext(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_all_contexts( + self, + ) -> Callable[[context.DeleteAllContextsRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteAllContexts(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_context( + self, + ) -> Callable[[context.DeleteContextRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteContext(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_context(self) -> Callable[[context.GetContextRequest], context.Context]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetContext(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_contexts( + self, + ) -> Callable[[context.ListContextsRequest], context.ListContextsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListContexts(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_context( + self, + ) -> Callable[[gcd_context.UpdateContextRequest], gcd_context.Context]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateContext(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ContextsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ContextsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ContextsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ContextsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ContextsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ContextsRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/conversation_profiles/client.py b/google/cloud/dialogflow_v2beta1/services/conversation_profiles/client.py index a5661f09e..7e928e469 100644 --- a/google/cloud/dialogflow_v2beta1/services/conversation_profiles/client.py +++ b/google/cloud/dialogflow_v2beta1/services/conversation_profiles/client.py @@ -63,6 +63,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, ConversationProfilesTransport from .transports.grpc import ConversationProfilesGrpcTransport from .transports.grpc_asyncio import ConversationProfilesGrpcAsyncIOTransport +from .transports.rest import ConversationProfilesRestTransport class ConversationProfilesClientMeta(type): @@ -78,6 +79,7 @@ class ConversationProfilesClientMeta(type): ) # type: Dict[str, Type[ConversationProfilesTransport]] _transport_registry["grpc"] = ConversationProfilesGrpcTransport _transport_registry["grpc_asyncio"] = ConversationProfilesGrpcAsyncIOTransport + _transport_registry["rest"] = ConversationProfilesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/conversation_profiles/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/conversation_profiles/transports/__init__.py index 969f74511..539a27c22 100644 --- a/google/cloud/dialogflow_v2beta1/services/conversation_profiles/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/conversation_profiles/transports/__init__.py @@ -19,6 +19,7 @@ from .base import ConversationProfilesTransport from .grpc import ConversationProfilesGrpcTransport from .grpc_asyncio import ConversationProfilesGrpcAsyncIOTransport +from .rest import ConversationProfilesRestInterceptor, ConversationProfilesRestTransport # Compile a registry of transports. _transport_registry = ( @@ -26,9 +27,12 @@ ) # type: Dict[str, Type[ConversationProfilesTransport]] _transport_registry["grpc"] = ConversationProfilesGrpcTransport _transport_registry["grpc_asyncio"] = ConversationProfilesGrpcAsyncIOTransport +_transport_registry["rest"] = ConversationProfilesRestTransport __all__ = ( "ConversationProfilesTransport", "ConversationProfilesGrpcTransport", "ConversationProfilesGrpcAsyncIOTransport", + "ConversationProfilesRestTransport", + "ConversationProfilesRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/conversation_profiles/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/conversation_profiles/transports/rest.py new file mode 100644 index 000000000..0415d00b2 --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/conversation_profiles/transports/rest.py @@ -0,0 +1,1722 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2beta1.types import ( + conversation_profile as gcd_conversation_profile, +) +from google.cloud.dialogflow_v2beta1.types import conversation_profile + +from .base import ConversationProfilesTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class ConversationProfilesRestInterceptor: + """Interceptor for ConversationProfiles. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the ConversationProfilesRestTransport. + + .. code-block:: python + class MyCustomConversationProfilesInterceptor(ConversationProfilesRestInterceptor): + def pre_clear_suggestion_feature_config(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_clear_suggestion_feature_config(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_conversation_profile(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_conversation_profile(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_conversation_profile(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_conversation_profile(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_conversation_profile(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_conversation_profiles(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_conversation_profiles(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_set_suggestion_feature_config(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_set_suggestion_feature_config(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_conversation_profile(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_conversation_profile(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ConversationProfilesRestTransport(interceptor=MyCustomConversationProfilesInterceptor()) + client = ConversationProfilesClient(transport=transport) + + + """ + + def pre_clear_suggestion_feature_config( + self, + request: gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for clear_suggestion_feature_config + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_clear_suggestion_feature_config( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for clear_suggestion_feature_config + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_create_conversation_profile( + self, + request: gcd_conversation_profile.CreateConversationProfileRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation_profile.CreateConversationProfileRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for create_conversation_profile + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_create_conversation_profile( + self, response: gcd_conversation_profile.ConversationProfile + ) -> gcd_conversation_profile.ConversationProfile: + """Post-rpc interceptor for create_conversation_profile + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_delete_conversation_profile( + self, + request: conversation_profile.DeleteConversationProfileRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_profile.DeleteConversationProfileRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for delete_conversation_profile + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def pre_get_conversation_profile( + self, + request: conversation_profile.GetConversationProfileRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_profile.GetConversationProfileRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for get_conversation_profile + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_get_conversation_profile( + self, response: conversation_profile.ConversationProfile + ) -> conversation_profile.ConversationProfile: + """Post-rpc interceptor for get_conversation_profile + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_list_conversation_profiles( + self, + request: conversation_profile.ListConversationProfilesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + conversation_profile.ListConversationProfilesRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for list_conversation_profiles + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_list_conversation_profiles( + self, response: conversation_profile.ListConversationProfilesResponse + ) -> conversation_profile.ListConversationProfilesResponse: + """Post-rpc interceptor for list_conversation_profiles + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_set_suggestion_feature_config( + self, + request: gcd_conversation_profile.SetSuggestionFeatureConfigRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation_profile.SetSuggestionFeatureConfigRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for set_suggestion_feature_config + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_set_suggestion_feature_config( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for set_suggestion_feature_config + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_update_conversation_profile( + self, + request: gcd_conversation_profile.UpdateConversationProfileRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation_profile.UpdateConversationProfileRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for update_conversation_profile + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_update_conversation_profile( + self, response: gcd_conversation_profile.ConversationProfile + ) -> gcd_conversation_profile.ConversationProfile: + """Post-rpc interceptor for update_conversation_profile + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the ConversationProfiles server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the ConversationProfiles server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ConversationProfilesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ConversationProfilesRestInterceptor + + +class ConversationProfilesRestTransport(ConversationProfilesTransport): + """REST backend transport for ConversationProfiles. + + Service for managing + [ConversationProfiles][google.cloud.dialogflow.v2beta1.ConversationProfile]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[ConversationProfilesRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or ConversationProfilesRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2beta1", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _ClearSuggestionFeatureConfig(ConversationProfilesRestStub): + def __hash__(self): + return hash("ClearSuggestionFeatureConfig") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the clear suggestion feature + config method over HTTP. + + Args: + request (~.gcd_conversation_profile.ClearSuggestionFeatureConfigRequest): + The request object. The request message for + [ConversationProfiles.ClearFeature][]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{conversation_profile=projects/*/conversationProfiles/*}:clearSuggestionFeatureConfig", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{conversation_profile=projects/*/locations/*/conversationProfiles/*}:clearSuggestionFeatureConfig", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_clear_suggestion_feature_config( + request, metadata + ) + pb_request = ( + gcd_conversation_profile.ClearSuggestionFeatureConfigRequest.pb(request) + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_clear_suggestion_feature_config(resp) + return resp + + class _CreateConversationProfile(ConversationProfilesRestStub): + def __hash__(self): + return hash("CreateConversationProfile") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation_profile.CreateConversationProfileRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_conversation_profile.ConversationProfile: + r"""Call the create conversation + profile method over HTTP. + + Args: + request (~.gcd_conversation_profile.CreateConversationProfileRequest): + The request object. The request message for + [ConversationProfiles.CreateConversationProfile][google.cloud.dialogflow.v2beta1.ConversationProfiles.CreateConversationProfile]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_conversation_profile.ConversationProfile: + Defines the services to connect to + incoming Dialogflow conversations. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*}/conversationProfiles", + "body": "conversation_profile", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*}/conversationProfiles", + "body": "conversation_profile", + }, + ] + request, metadata = self._interceptor.pre_create_conversation_profile( + request, metadata + ) + pb_request = gcd_conversation_profile.CreateConversationProfileRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_conversation_profile.ConversationProfile() + pb_resp = gcd_conversation_profile.ConversationProfile.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_conversation_profile(resp) + return resp + + class _DeleteConversationProfile(ConversationProfilesRestStub): + def __hash__(self): + return hash("DeleteConversationProfile") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_profile.DeleteConversationProfileRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete conversation + profile method over HTTP. + + Args: + request (~.conversation_profile.DeleteConversationProfileRequest): + The request object. The request message for + [ConversationProfiles.DeleteConversationProfile][google.cloud.dialogflow.v2beta1.ConversationProfiles.DeleteConversationProfile]. + + This operation fails if the conversation profile is + still referenced from a phone number. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/conversationProfiles/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/locations/*/conversationProfiles/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_conversation_profile( + request, metadata + ) + pb_request = conversation_profile.DeleteConversationProfileRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetConversationProfile(ConversationProfilesRestStub): + def __hash__(self): + return hash("GetConversationProfile") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_profile.GetConversationProfileRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation_profile.ConversationProfile: + r"""Call the get conversation profile method over HTTP. + + Args: + request (~.conversation_profile.GetConversationProfileRequest): + The request object. The request message for + [ConversationProfiles.GetConversationProfile][google.cloud.dialogflow.v2beta1.ConversationProfiles.GetConversationProfile]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation_profile.ConversationProfile: + Defines the services to connect to + incoming Dialogflow conversations. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/conversationProfiles/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/conversationProfiles/*}", + }, + ] + request, metadata = self._interceptor.pre_get_conversation_profile( + request, metadata + ) + pb_request = conversation_profile.GetConversationProfileRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation_profile.ConversationProfile() + pb_resp = conversation_profile.ConversationProfile.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_conversation_profile(resp) + return resp + + class _ListConversationProfiles(ConversationProfilesRestStub): + def __hash__(self): + return hash("ListConversationProfiles") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation_profile.ListConversationProfilesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation_profile.ListConversationProfilesResponse: + r"""Call the list conversation + profiles method over HTTP. + + Args: + request (~.conversation_profile.ListConversationProfilesRequest): + The request object. The request message for + [ConversationProfiles.ListConversationProfiles][google.cloud.dialogflow.v2beta1.ConversationProfiles.ListConversationProfiles]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation_profile.ListConversationProfilesResponse: + The response message for + [ConversationProfiles.ListConversationProfiles][google.cloud.dialogflow.v2beta1.ConversationProfiles.ListConversationProfiles]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*}/conversationProfiles", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*}/conversationProfiles", + }, + ] + request, metadata = self._interceptor.pre_list_conversation_profiles( + request, metadata + ) + pb_request = conversation_profile.ListConversationProfilesRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation_profile.ListConversationProfilesResponse() + pb_resp = conversation_profile.ListConversationProfilesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_conversation_profiles(resp) + return resp + + class _SetSuggestionFeatureConfig(ConversationProfilesRestStub): + def __hash__(self): + return hash("SetSuggestionFeatureConfig") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation_profile.SetSuggestionFeatureConfigRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the set suggestion feature + config method over HTTP. + + Args: + request (~.gcd_conversation_profile.SetSuggestionFeatureConfigRequest): + The request object. The request message for + [ConversationProfiles.SetSuggestionFeature][]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{conversation_profile=projects/*/conversationProfiles/*}:setSuggestionFeatureConfig", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{conversation_profile=projects/*/locations/*/conversationProfiles/*}:setSuggestionFeatureConfig", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_set_suggestion_feature_config( + request, metadata + ) + pb_request = gcd_conversation_profile.SetSuggestionFeatureConfigRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_set_suggestion_feature_config(resp) + return resp + + class _UpdateConversationProfile(ConversationProfilesRestStub): + def __hash__(self): + return hash("UpdateConversationProfile") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation_profile.UpdateConversationProfileRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_conversation_profile.ConversationProfile: + r"""Call the update conversation + profile method over HTTP. + + Args: + request (~.gcd_conversation_profile.UpdateConversationProfileRequest): + The request object. The request message for + [ConversationProfiles.UpdateConversationProfile][google.cloud.dialogflow.v2beta1.ConversationProfiles.UpdateConversationProfile]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_conversation_profile.ConversationProfile: + Defines the services to connect to + incoming Dialogflow conversations. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{conversation_profile.name=projects/*/conversationProfiles/*}", + "body": "conversation_profile", + }, + { + "method": "patch", + "uri": "/v2beta1/{conversation_profile.name=projects/*/locations/*/conversationProfiles/*}", + "body": "conversation_profile", + }, + ] + request, metadata = self._interceptor.pre_update_conversation_profile( + request, metadata + ) + pb_request = gcd_conversation_profile.UpdateConversationProfileRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_conversation_profile.ConversationProfile() + pb_resp = gcd_conversation_profile.ConversationProfile.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_conversation_profile(resp) + return resp + + @property + def clear_suggestion_feature_config( + self, + ) -> Callable[ + [gcd_conversation_profile.ClearSuggestionFeatureConfigRequest], + operations_pb2.Operation, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ClearSuggestionFeatureConfig(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_conversation_profile( + self, + ) -> Callable[ + [gcd_conversation_profile.CreateConversationProfileRequest], + gcd_conversation_profile.ConversationProfile, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateConversationProfile(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_conversation_profile( + self, + ) -> Callable[ + [conversation_profile.DeleteConversationProfileRequest], empty_pb2.Empty + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteConversationProfile(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_conversation_profile( + self, + ) -> Callable[ + [conversation_profile.GetConversationProfileRequest], + conversation_profile.ConversationProfile, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetConversationProfile(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_conversation_profiles( + self, + ) -> Callable[ + [conversation_profile.ListConversationProfilesRequest], + conversation_profile.ListConversationProfilesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListConversationProfiles(self._session, self._host, self._interceptor) # type: ignore + + @property + def set_suggestion_feature_config( + self, + ) -> Callable[ + [gcd_conversation_profile.SetSuggestionFeatureConfigRequest], + operations_pb2.Operation, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SetSuggestionFeatureConfig(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_conversation_profile( + self, + ) -> Callable[ + [gcd_conversation_profile.UpdateConversationProfileRequest], + gcd_conversation_profile.ConversationProfile, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateConversationProfile(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ConversationProfilesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ConversationProfilesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ConversationProfilesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ConversationProfilesRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ConversationProfilesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ConversationProfilesRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/conversations/client.py b/google/cloud/dialogflow_v2beta1/services/conversations/client.py index 315e37252..f241a6030 100644 --- a/google/cloud/dialogflow_v2beta1/services/conversations/client.py +++ b/google/cloud/dialogflow_v2beta1/services/conversations/client.py @@ -58,6 +58,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, ConversationsTransport from .transports.grpc import ConversationsGrpcTransport from .transports.grpc_asyncio import ConversationsGrpcAsyncIOTransport +from .transports.rest import ConversationsRestTransport class ConversationsClientMeta(type): @@ -71,6 +72,7 @@ class ConversationsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[ConversationsTransport]] _transport_registry["grpc"] = ConversationsGrpcTransport _transport_registry["grpc_asyncio"] = ConversationsGrpcAsyncIOTransport + _transport_registry["rest"] = ConversationsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/conversations/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/conversations/transports/__init__.py index 4124c89ab..1b2e228b6 100644 --- a/google/cloud/dialogflow_v2beta1/services/conversations/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/conversations/transports/__init__.py @@ -19,14 +19,18 @@ from .base import ConversationsTransport from .grpc import ConversationsGrpcTransport from .grpc_asyncio import ConversationsGrpcAsyncIOTransport +from .rest import ConversationsRestInterceptor, ConversationsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[ConversationsTransport]] _transport_registry["grpc"] = ConversationsGrpcTransport _transport_registry["grpc_asyncio"] = ConversationsGrpcAsyncIOTransport +_transport_registry["rest"] = ConversationsRestTransport __all__ = ( "ConversationsTransport", "ConversationsGrpcTransport", "ConversationsGrpcAsyncIOTransport", + "ConversationsRestTransport", + "ConversationsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/conversations/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/conversations/transports/rest.py new file mode 100644 index 000000000..dc975c352 --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/conversations/transports/rest.py @@ -0,0 +1,1652 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.dialogflow_v2beta1.types import conversation as gcd_conversation +from google.cloud.dialogflow_v2beta1.types import conversation + +from .base import ConversationsTransport +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class ConversationsRestInterceptor: + """Interceptor for Conversations. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the ConversationsRestTransport. + + .. code-block:: python + class MyCustomConversationsInterceptor(ConversationsRestInterceptor): + def pre_batch_create_messages(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_create_messages(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_complete_conversation(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_complete_conversation(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_conversation(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_conversation(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_conversation(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_conversation(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_conversations(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_conversations(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_messages(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_messages(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_suggest_conversation_summary(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_suggest_conversation_summary(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ConversationsRestTransport(interceptor=MyCustomConversationsInterceptor()) + client = ConversationsClient(transport=transport) + + + """ + + def pre_batch_create_messages( + self, + request: conversation.BatchCreateMessagesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[conversation.BatchCreateMessagesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_create_messages + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_batch_create_messages( + self, response: conversation.BatchCreateMessagesResponse + ) -> conversation.BatchCreateMessagesResponse: + """Post-rpc interceptor for batch_create_messages + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_complete_conversation( + self, + request: conversation.CompleteConversationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[conversation.CompleteConversationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for complete_conversation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_complete_conversation( + self, response: conversation.Conversation + ) -> conversation.Conversation: + """Post-rpc interceptor for complete_conversation + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_create_conversation( + self, + request: gcd_conversation.CreateConversationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_conversation.CreateConversationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_conversation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_create_conversation( + self, response: gcd_conversation.Conversation + ) -> gcd_conversation.Conversation: + """Post-rpc interceptor for create_conversation + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_get_conversation( + self, + request: conversation.GetConversationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[conversation.GetConversationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_conversation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_get_conversation( + self, response: conversation.Conversation + ) -> conversation.Conversation: + """Post-rpc interceptor for get_conversation + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_list_conversations( + self, + request: conversation.ListConversationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[conversation.ListConversationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_conversations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_list_conversations( + self, response: conversation.ListConversationsResponse + ) -> conversation.ListConversationsResponse: + """Post-rpc interceptor for list_conversations + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_list_messages( + self, + request: conversation.ListMessagesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[conversation.ListMessagesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_messages + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_list_messages( + self, response: conversation.ListMessagesResponse + ) -> conversation.ListMessagesResponse: + """Post-rpc interceptor for list_messages + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_suggest_conversation_summary( + self, + request: gcd_conversation.SuggestConversationSummaryRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_conversation.SuggestConversationSummaryRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for suggest_conversation_summary + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_suggest_conversation_summary( + self, response: gcd_conversation.SuggestConversationSummaryResponse + ) -> gcd_conversation.SuggestConversationSummaryResponse: + """Post-rpc interceptor for suggest_conversation_summary + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Conversations server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Conversations server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ConversationsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ConversationsRestInterceptor + + +class ConversationsRestTransport(ConversationsTransport): + """REST backend transport for Conversations. + + Service for managing + [Conversations][google.cloud.dialogflow.v2beta1.Conversation]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[ConversationsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or ConversationsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _BatchCreateMessages(ConversationsRestStub): + def __hash__(self): + return hash("BatchCreateMessages") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation.BatchCreateMessagesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation.BatchCreateMessagesResponse: + r"""Call the batch create messages method over HTTP. + + Args: + request (~.conversation.BatchCreateMessagesRequest): + The request object. The request message for + [Conversations.BatchCreateMessagesRequest][]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation.BatchCreateMessagesResponse: + The request message for + [Conversations.BatchCreateMessagesResponse][]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/conversations/*}/messages:batchCreate", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/conversations/*}/messages:batchCreate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_create_messages( + request, metadata + ) + pb_request = conversation.BatchCreateMessagesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation.BatchCreateMessagesResponse() + pb_resp = conversation.BatchCreateMessagesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_create_messages(resp) + return resp + + class _CompleteConversation(ConversationsRestStub): + def __hash__(self): + return hash("CompleteConversation") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation.CompleteConversationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation.Conversation: + r"""Call the complete conversation method over HTTP. + + Args: + request (~.conversation.CompleteConversationRequest): + The request object. The request message for + [Conversations.CompleteConversation][google.cloud.dialogflow.v2beta1.Conversations.CompleteConversation]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation.Conversation: + Represents a conversation. + A conversation is an interaction between + an agent, including live agents and + Dialogflow agents, and a support + customer. Conversations can include + phone calls and text-based chat + sessions. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/conversations/*}:complete", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/conversations/*}:complete", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_complete_conversation( + request, metadata + ) + pb_request = conversation.CompleteConversationRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation.Conversation() + pb_resp = conversation.Conversation.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_complete_conversation(resp) + return resp + + class _CreateConversation(ConversationsRestStub): + def __hash__(self): + return hash("CreateConversation") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation.CreateConversationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_conversation.Conversation: + r"""Call the create conversation method over HTTP. + + Args: + request (~.gcd_conversation.CreateConversationRequest): + The request object. The request message for + [Conversations.CreateConversation][google.cloud.dialogflow.v2beta1.Conversations.CreateConversation]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_conversation.Conversation: + Represents a conversation. + A conversation is an interaction between + an agent, including live agents and + Dialogflow agents, and a support + customer. Conversations can include + phone calls and text-based chat + sessions. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*}/conversations", + "body": "conversation", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*}/conversations", + "body": "conversation", + }, + ] + request, metadata = self._interceptor.pre_create_conversation( + request, metadata + ) + pb_request = gcd_conversation.CreateConversationRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_conversation.Conversation() + pb_resp = gcd_conversation.Conversation.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_conversation(resp) + return resp + + class _GetConversation(ConversationsRestStub): + def __hash__(self): + return hash("GetConversation") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation.GetConversationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation.Conversation: + r"""Call the get conversation method over HTTP. + + Args: + request (~.conversation.GetConversationRequest): + The request object. The request message for + [Conversations.GetConversation][google.cloud.dialogflow.v2beta1.Conversations.GetConversation]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation.Conversation: + Represents a conversation. + A conversation is an interaction between + an agent, including live agents and + Dialogflow agents, and a support + customer. Conversations can include + phone calls and text-based chat + sessions. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/conversations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/conversations/*}", + }, + ] + request, metadata = self._interceptor.pre_get_conversation( + request, metadata + ) + pb_request = conversation.GetConversationRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation.Conversation() + pb_resp = conversation.Conversation.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_conversation(resp) + return resp + + class _ListConversations(ConversationsRestStub): + def __hash__(self): + return hash("ListConversations") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation.ListConversationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation.ListConversationsResponse: + r"""Call the list conversations method over HTTP. + + Args: + request (~.conversation.ListConversationsRequest): + The request object. The request message for + [Conversations.ListConversations][google.cloud.dialogflow.v2beta1.Conversations.ListConversations]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation.ListConversationsResponse: + The response message for + [Conversations.ListConversations][google.cloud.dialogflow.v2beta1.Conversations.ListConversations]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*}/conversations", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*}/conversations", + }, + ] + request, metadata = self._interceptor.pre_list_conversations( + request, metadata + ) + pb_request = conversation.ListConversationsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation.ListConversationsResponse() + pb_resp = conversation.ListConversationsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_conversations(resp) + return resp + + class _ListMessages(ConversationsRestStub): + def __hash__(self): + return hash("ListMessages") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: conversation.ListMessagesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> conversation.ListMessagesResponse: + r"""Call the list messages method over HTTP. + + Args: + request (~.conversation.ListMessagesRequest): + The request object. The request message for + [Conversations.ListMessages][google.cloud.dialogflow.v2beta1.Conversations.ListMessages]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.conversation.ListMessagesResponse: + The response message for + [Conversations.ListMessages][google.cloud.dialogflow.v2beta1.Conversations.ListMessages]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/conversations/*}/messages", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/conversations/*}/messages", + }, + ] + request, metadata = self._interceptor.pre_list_messages(request, metadata) + pb_request = conversation.ListMessagesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = conversation.ListMessagesResponse() + pb_resp = conversation.ListMessagesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_messages(resp) + return resp + + class _SuggestConversationSummary(ConversationsRestStub): + def __hash__(self): + return hash("SuggestConversationSummary") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_conversation.SuggestConversationSummaryRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_conversation.SuggestConversationSummaryResponse: + r"""Call the suggest conversation + summary method over HTTP. + + Args: + request (~.gcd_conversation.SuggestConversationSummaryRequest): + The request object. The request message for + [Conversations.SuggestConversationSummary][google.cloud.dialogflow.v2beta1.Conversations.SuggestConversationSummary]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_conversation.SuggestConversationSummaryResponse: + The response message for + [Conversations.SuggestConversationSummary][google.cloud.dialogflow.v2beta1.Conversations.SuggestConversationSummary]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{conversation=projects/*/conversations/*}/suggestions:suggestConversationSummary", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{conversation=projects/*/locations/*/conversations/*}/suggestions:suggestConversationSummary", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_suggest_conversation_summary( + request, metadata + ) + pb_request = gcd_conversation.SuggestConversationSummaryRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_conversation.SuggestConversationSummaryResponse() + pb_resp = gcd_conversation.SuggestConversationSummaryResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_suggest_conversation_summary(resp) + return resp + + @property + def batch_create_messages( + self, + ) -> Callable[ + [conversation.BatchCreateMessagesRequest], + conversation.BatchCreateMessagesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchCreateMessages(self._session, self._host, self._interceptor) # type: ignore + + @property + def complete_conversation( + self, + ) -> Callable[ + [conversation.CompleteConversationRequest], conversation.Conversation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CompleteConversation(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_conversation( + self, + ) -> Callable[ + [gcd_conversation.CreateConversationRequest], gcd_conversation.Conversation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateConversation(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_conversation( + self, + ) -> Callable[[conversation.GetConversationRequest], conversation.Conversation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetConversation(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_conversations( + self, + ) -> Callable[ + [conversation.ListConversationsRequest], conversation.ListConversationsResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListConversations(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_messages( + self, + ) -> Callable[ + [conversation.ListMessagesRequest], conversation.ListMessagesResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListMessages(self._session, self._host, self._interceptor) # type: ignore + + @property + def suggest_conversation_summary( + self, + ) -> Callable[ + [gcd_conversation.SuggestConversationSummaryRequest], + gcd_conversation.SuggestConversationSummaryResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SuggestConversationSummary(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ConversationsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ConversationsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ConversationsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ConversationsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ConversationsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ConversationsRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/documents/client.py b/google/cloud/dialogflow_v2beta1/services/documents/client.py index 741d0d47e..7a0e877b8 100644 --- a/google/cloud/dialogflow_v2beta1/services/documents/client.py +++ b/google/cloud/dialogflow_v2beta1/services/documents/client.py @@ -61,6 +61,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, DocumentsTransport from .transports.grpc import DocumentsGrpcTransport from .transports.grpc_asyncio import DocumentsGrpcAsyncIOTransport +from .transports.rest import DocumentsRestTransport class DocumentsClientMeta(type): @@ -74,6 +75,7 @@ class DocumentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[DocumentsTransport]] _transport_registry["grpc"] = DocumentsGrpcTransport _transport_registry["grpc_asyncio"] = DocumentsGrpcAsyncIOTransport + _transport_registry["rest"] = DocumentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/documents/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/documents/transports/__init__.py index 5d938d116..d0736cf39 100644 --- a/google/cloud/dialogflow_v2beta1/services/documents/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/documents/transports/__init__.py @@ -19,14 +19,18 @@ from .base import DocumentsTransport from .grpc import DocumentsGrpcTransport from .grpc_asyncio import DocumentsGrpcAsyncIOTransport +from .rest import DocumentsRestInterceptor, DocumentsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[DocumentsTransport]] _transport_registry["grpc"] = DocumentsGrpcTransport _transport_registry["grpc_asyncio"] = DocumentsGrpcAsyncIOTransport +_transport_registry["rest"] = DocumentsRestTransport __all__ = ( "DocumentsTransport", "DocumentsGrpcTransport", "DocumentsGrpcAsyncIOTransport", + "DocumentsRestTransport", + "DocumentsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/documents/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/documents/transports/rest.py new file mode 100644 index 000000000..d00311d77 --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/documents/transports/rest.py @@ -0,0 +1,1702 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore + +from google.cloud.dialogflow_v2beta1.types import document +from google.cloud.dialogflow_v2beta1.types import document as gcd_document + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import DocumentsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class DocumentsRestInterceptor: + """Interceptor for Documents. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the DocumentsRestTransport. + + .. code-block:: python + class MyCustomDocumentsInterceptor(DocumentsRestInterceptor): + def pre_create_document(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_document(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_document(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_delete_document(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_document(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_document(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_import_documents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_import_documents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_documents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_documents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_reload_document(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_reload_document(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_document(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_document(self, response): + logging.log(f"Received response: {response}") + return response + + transport = DocumentsRestTransport(interceptor=MyCustomDocumentsInterceptor()) + client = DocumentsClient(transport=transport) + + + """ + + def pre_create_document( + self, + request: gcd_document.CreateDocumentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_document.CreateDocumentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_document + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_create_document( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for create_document + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_delete_document( + self, + request: document.DeleteDocumentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[document.DeleteDocumentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_document + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_delete_document( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for delete_document + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_get_document( + self, request: document.GetDocumentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[document.GetDocumentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_document + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_get_document(self, response: document.Document) -> document.Document: + """Post-rpc interceptor for get_document + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_import_documents( + self, + request: document.ImportDocumentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[document.ImportDocumentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for import_documents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_import_documents( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for import_documents + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_list_documents( + self, + request: document.ListDocumentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[document.ListDocumentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_documents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_list_documents( + self, response: document.ListDocumentsResponse + ) -> document.ListDocumentsResponse: + """Post-rpc interceptor for list_documents + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_reload_document( + self, + request: document.ReloadDocumentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[document.ReloadDocumentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for reload_document + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_reload_document( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for reload_document + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_update_document( + self, + request: gcd_document.UpdateDocumentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_document.UpdateDocumentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_document + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_update_document( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for update_document + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Documents server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Documents server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class DocumentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: DocumentsRestInterceptor + + +class DocumentsRestTransport(DocumentsTransport): + """REST backend transport for Documents. + + Service for managing knowledge + [Documents][google.cloud.dialogflow.v2beta1.Document]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[DocumentsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or DocumentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2beta1", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _CreateDocument(DocumentsRestStub): + def __hash__(self): + return hash("CreateDocument") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_document.CreateDocumentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the create document method over HTTP. + + Args: + request (~.gcd_document.CreateDocumentRequest): + The request object. Request message for + [Documents.CreateDocument][google.cloud.dialogflow.v2beta1.Documents.CreateDocument]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/knowledgeBases/*}/documents", + "body": "document", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/knowledgeBases/*}/documents", + "body": "document", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent/knowledgeBases/*}/documents", + "body": "document", + }, + ] + request, metadata = self._interceptor.pre_create_document(request, metadata) + pb_request = gcd_document.CreateDocumentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_document(resp) + return resp + + class _DeleteDocument(DocumentsRestStub): + def __hash__(self): + return hash("DeleteDocument") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: document.DeleteDocumentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the delete document method over HTTP. + + Args: + request (~.document.DeleteDocumentRequest): + The request object. Request message for + [Documents.DeleteDocument][google.cloud.dialogflow.v2beta1.Documents.DeleteDocument]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/knowledgeBases/*/documents/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/locations/*/knowledgeBases/*/documents/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/agent/knowledgeBases/*/documents/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_document(request, metadata) + pb_request = document.DeleteDocumentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_delete_document(resp) + return resp + + class _GetDocument(DocumentsRestStub): + def __hash__(self): + return hash("GetDocument") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: document.GetDocumentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> document.Document: + r"""Call the get document method over HTTP. + + Args: + request (~.document.GetDocumentRequest): + The request object. Request message for + [Documents.GetDocument][google.cloud.dialogflow.v2beta1.Documents.GetDocument]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.document.Document: + A knowledge document to be used by a + [KnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBase]. + + For more information, see the `knowledge base + guide `__. + + Note: The ``projects.agent.knowledgeBases.documents`` + resource is deprecated; only use + ``projects.knowledgeBases.documents``. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/knowledgeBases/*/documents/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/knowledgeBases/*/documents/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/agent/knowledgeBases/*/documents/*}", + }, + ] + request, metadata = self._interceptor.pre_get_document(request, metadata) + pb_request = document.GetDocumentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = document.Document() + pb_resp = document.Document.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_document(resp) + return resp + + class _ImportDocuments(DocumentsRestStub): + def __hash__(self): + return hash("ImportDocuments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: document.ImportDocumentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the import documents method over HTTP. + + Args: + request (~.document.ImportDocumentsRequest): + The request object. Request message for + [Documents.ImportDocuments][google.cloud.dialogflow.v2beta1.Documents.ImportDocuments]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/knowledgeBases/*}/documents:import", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/knowledgeBases/*}/documents:import", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_import_documents( + request, metadata + ) + pb_request = document.ImportDocumentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_import_documents(resp) + return resp + + class _ListDocuments(DocumentsRestStub): + def __hash__(self): + return hash("ListDocuments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: document.ListDocumentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> document.ListDocumentsResponse: + r"""Call the list documents method over HTTP. + + Args: + request (~.document.ListDocumentsRequest): + The request object. Request message for + [Documents.ListDocuments][google.cloud.dialogflow.v2beta1.Documents.ListDocuments]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.document.ListDocumentsResponse: + Response message for + [Documents.ListDocuments][google.cloud.dialogflow.v2beta1.Documents.ListDocuments]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/knowledgeBases/*}/documents", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/knowledgeBases/*}/documents", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent/knowledgeBases/*}/documents", + }, + ] + request, metadata = self._interceptor.pre_list_documents(request, metadata) + pb_request = document.ListDocumentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = document.ListDocumentsResponse() + pb_resp = document.ListDocumentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_documents(resp) + return resp + + class _ReloadDocument(DocumentsRestStub): + def __hash__(self): + return hash("ReloadDocument") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: document.ReloadDocumentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the reload document method over HTTP. + + Args: + request (~.document.ReloadDocumentRequest): + The request object. Request message for + [Documents.ReloadDocument][google.cloud.dialogflow.v2beta1.Documents.ReloadDocument]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/knowledgeBases/*/documents/*}:reload", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/knowledgeBases/*/documents/*}:reload", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/agent/knowledgeBases/*/documents/*}:reload", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_reload_document(request, metadata) + pb_request = document.ReloadDocumentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_reload_document(resp) + return resp + + class _UpdateDocument(DocumentsRestStub): + def __hash__(self): + return hash("UpdateDocument") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_document.UpdateDocumentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the update document method over HTTP. + + Args: + request (~.gcd_document.UpdateDocumentRequest): + The request object. Request message for + [Documents.UpdateDocument][google.cloud.dialogflow.v2beta1.Documents.UpdateDocument]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{document.name=projects/*/knowledgeBases/*/documents/*}", + "body": "document", + }, + { + "method": "patch", + "uri": "/v2beta1/{document.name=projects/*/locations/*/knowledgeBases/*/documents/*}", + "body": "document", + }, + { + "method": "patch", + "uri": "/v2beta1/{document.name=projects/*/agent/knowledgeBases/*/documents/*}", + "body": "document", + }, + ] + request, metadata = self._interceptor.pre_update_document(request, metadata) + pb_request = gcd_document.UpdateDocumentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_document(resp) + return resp + + @property + def create_document( + self, + ) -> Callable[[gcd_document.CreateDocumentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateDocument(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_document( + self, + ) -> Callable[[document.DeleteDocumentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteDocument(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_document( + self, + ) -> Callable[[document.GetDocumentRequest], document.Document]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetDocument(self._session, self._host, self._interceptor) # type: ignore + + @property + def import_documents( + self, + ) -> Callable[[document.ImportDocumentsRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ImportDocuments(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_documents( + self, + ) -> Callable[[document.ListDocumentsRequest], document.ListDocumentsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListDocuments(self._session, self._host, self._interceptor) # type: ignore + + @property + def reload_document( + self, + ) -> Callable[[document.ReloadDocumentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ReloadDocument(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_document( + self, + ) -> Callable[[gcd_document.UpdateDocumentRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateDocument(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(DocumentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(DocumentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(DocumentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(DocumentsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(DocumentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("DocumentsRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/entity_types/client.py b/google/cloud/dialogflow_v2beta1/services/entity_types/client.py index fef0646c9..ffc64bfeb 100644 --- a/google/cloud/dialogflow_v2beta1/services/entity_types/client.py +++ b/google/cloud/dialogflow_v2beta1/services/entity_types/client.py @@ -61,6 +61,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, EntityTypesTransport from .transports.grpc import EntityTypesGrpcTransport from .transports.grpc_asyncio import EntityTypesGrpcAsyncIOTransport +from .transports.rest import EntityTypesRestTransport class EntityTypesClientMeta(type): @@ -74,6 +75,7 @@ class EntityTypesClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[EntityTypesTransport]] _transport_registry["grpc"] = EntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = EntityTypesGrpcAsyncIOTransport + _transport_registry["rest"] = EntityTypesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/entity_types/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/entity_types/transports/__init__.py index 68efe567e..c60b49aa5 100644 --- a/google/cloud/dialogflow_v2beta1/services/entity_types/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/entity_types/transports/__init__.py @@ -19,14 +19,18 @@ from .base import EntityTypesTransport from .grpc import EntityTypesGrpcTransport from .grpc_asyncio import EntityTypesGrpcAsyncIOTransport +from .rest import EntityTypesRestInterceptor, EntityTypesRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[EntityTypesTransport]] _transport_registry["grpc"] = EntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = EntityTypesGrpcAsyncIOTransport +_transport_registry["rest"] = EntityTypesRestTransport __all__ = ( "EntityTypesTransport", "EntityTypesGrpcTransport", "EntityTypesGrpcAsyncIOTransport", + "EntityTypesRestTransport", + "EntityTypesRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/entity_types/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/entity_types/transports/rest.py new file mode 100644 index 000000000..9f8407b52 --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/entity_types/transports/rest.py @@ -0,0 +1,2138 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2beta1.types import entity_type as gcd_entity_type +from google.cloud.dialogflow_v2beta1.types import entity_type + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import EntityTypesTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class EntityTypesRestInterceptor: + """Interceptor for EntityTypes. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the EntityTypesRestTransport. + + .. code-block:: python + class MyCustomEntityTypesInterceptor(EntityTypesRestInterceptor): + def pre_batch_create_entities(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_create_entities(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_delete_entities(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_delete_entities(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_delete_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_delete_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_update_entities(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_update_entities(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_update_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_update_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + transport = EntityTypesRestTransport(interceptor=MyCustomEntityTypesInterceptor()) + client = EntityTypesClient(transport=transport) + + + """ + + def pre_batch_create_entities( + self, + request: entity_type.BatchCreateEntitiesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.BatchCreateEntitiesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_create_entities + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_batch_create_entities( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_create_entities + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_batch_delete_entities( + self, + request: entity_type.BatchDeleteEntitiesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.BatchDeleteEntitiesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_delete_entities + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_batch_delete_entities( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_delete_entities + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_batch_delete_entity_types( + self, + request: entity_type.BatchDeleteEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.BatchDeleteEntityTypesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_delete_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_batch_delete_entity_types( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_delete_entity_types + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_batch_update_entities( + self, + request: entity_type.BatchUpdateEntitiesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.BatchUpdateEntitiesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_update_entities + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_batch_update_entities( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_update_entities + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_batch_update_entity_types( + self, + request: entity_type.BatchUpdateEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.BatchUpdateEntityTypesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_update_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_batch_update_entity_types( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_update_entity_types + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_create_entity_type( + self, + request: gcd_entity_type.CreateEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_entity_type.CreateEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_create_entity_type( + self, response: gcd_entity_type.EntityType + ) -> gcd_entity_type.EntityType: + """Post-rpc interceptor for create_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_delete_entity_type( + self, + request: entity_type.DeleteEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.DeleteEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def pre_get_entity_type( + self, + request: entity_type.GetEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.GetEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_entity_type( + self, response: entity_type.EntityType + ) -> entity_type.EntityType: + """Post-rpc interceptor for get_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_entity_types( + self, + request: entity_type.ListEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[entity_type.ListEntityTypesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_entity_types( + self, response: entity_type.ListEntityTypesResponse + ) -> entity_type.ListEntityTypesResponse: + """Post-rpc interceptor for list_entity_types + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_update_entity_type( + self, + request: gcd_entity_type.UpdateEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_entity_type.UpdateEntityTypeRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_update_entity_type( + self, response: gcd_entity_type.EntityType + ) -> gcd_entity_type.EntityType: + """Post-rpc interceptor for update_entity_type + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the EntityTypes server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the EntityTypes server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class EntityTypesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: EntityTypesRestInterceptor + + +class EntityTypesRestTransport(EntityTypesTransport): + """REST backend transport for EntityTypes. + + Service for managing + [EntityTypes][google.cloud.dialogflow.v2beta1.EntityType]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[EntityTypesRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or EntityTypesRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2beta1", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _BatchCreateEntities(EntityTypesRestStub): + def __hash__(self): + return hash("BatchCreateEntities") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.BatchCreateEntitiesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch create entities method over HTTP. + + Args: + request (~.entity_type.BatchCreateEntitiesRequest): + The request object. The request message for + [EntityTypes.BatchCreateEntities][google.cloud.dialogflow.v2beta1.EntityTypes.BatchCreateEntities]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent/entityTypes/*}/entities:batchCreate", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/entityTypes/*}/entities:batchCreate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_create_entities( + request, metadata + ) + pb_request = entity_type.BatchCreateEntitiesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_create_entities(resp) + return resp + + class _BatchDeleteEntities(EntityTypesRestStub): + def __hash__(self): + return hash("BatchDeleteEntities") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.BatchDeleteEntitiesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch delete entities method over HTTP. + + Args: + request (~.entity_type.BatchDeleteEntitiesRequest): + The request object. The request message for + [EntityTypes.BatchDeleteEntities][google.cloud.dialogflow.v2beta1.EntityTypes.BatchDeleteEntities]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent/entityTypes/*}/entities:batchDelete", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/entityTypes/*}/entities:batchDelete", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_delete_entities( + request, metadata + ) + pb_request = entity_type.BatchDeleteEntitiesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_delete_entities(resp) + return resp + + class _BatchDeleteEntityTypes(EntityTypesRestStub): + def __hash__(self): + return hash("BatchDeleteEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.BatchDeleteEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch delete entity types method over HTTP. + + Args: + request (~.entity_type.BatchDeleteEntityTypesRequest): + The request object. The request message for + [EntityTypes.BatchDeleteEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.BatchDeleteEntityTypes]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent}/entityTypes:batchDelete", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/entityTypes:batchDelete", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_delete_entity_types( + request, metadata + ) + pb_request = entity_type.BatchDeleteEntityTypesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_delete_entity_types(resp) + return resp + + class _BatchUpdateEntities(EntityTypesRestStub): + def __hash__(self): + return hash("BatchUpdateEntities") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.BatchUpdateEntitiesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch update entities method over HTTP. + + Args: + request (~.entity_type.BatchUpdateEntitiesRequest): + The request object. The request message for + [EntityTypes.BatchUpdateEntities][google.cloud.dialogflow.v2beta1.EntityTypes.BatchUpdateEntities]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent/entityTypes/*}/entities:batchUpdate", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/entityTypes/*}/entities:batchUpdate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_update_entities( + request, metadata + ) + pb_request = entity_type.BatchUpdateEntitiesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_update_entities(resp) + return resp + + class _BatchUpdateEntityTypes(EntityTypesRestStub): + def __hash__(self): + return hash("BatchUpdateEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.BatchUpdateEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch update entity types method over HTTP. + + Args: + request (~.entity_type.BatchUpdateEntityTypesRequest): + The request object. The request message for + [EntityTypes.BatchUpdateEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.BatchUpdateEntityTypes]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent}/entityTypes:batchUpdate", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/entityTypes:batchUpdate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_update_entity_types( + request, metadata + ) + pb_request = entity_type.BatchUpdateEntityTypesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_update_entity_types(resp) + return resp + + class _CreateEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("CreateEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_entity_type.CreateEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_entity_type.EntityType: + r"""Call the create entity type method over HTTP. + + Args: + request (~.gcd_entity_type.CreateEntityTypeRequest): + The request object. The request message for + [EntityTypes.CreateEntityType][google.cloud.dialogflow.v2beta1.EntityTypes.CreateEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_entity_type.EntityType: + Each intent parameter has a type, called the entity + type, which dictates exactly how data from an end-user + expression is extracted. + + Dialogflow provides predefined system entities that can + match many common types of data. For example, there are + system entities for matching dates, times, colors, email + addresses, and so on. You can also create your own + custom entities for matching custom data. For example, + you could define a vegetable entity that can match the + types of vegetables available for purchase with a + grocery store agent. + + For more information, see the `Entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent}/entityTypes", + "body": "entity_type", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/entityTypes", + "body": "entity_type", + }, + ] + request, metadata = self._interceptor.pre_create_entity_type( + request, metadata + ) + pb_request = gcd_entity_type.CreateEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_entity_type.EntityType() + pb_resp = gcd_entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_entity_type(resp) + return resp + + class _DeleteEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("DeleteEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.DeleteEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete entity type method over HTTP. + + Args: + request (~.entity_type.DeleteEntityTypeRequest): + The request object. The request message for + [EntityTypes.DeleteEntityType][google.cloud.dialogflow.v2beta1.EntityTypes.DeleteEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/agent/entityTypes/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_entity_type( + request, metadata + ) + pb_request = entity_type.DeleteEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("GetEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.GetEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> entity_type.EntityType: + r"""Call the get entity type method over HTTP. + + Args: + request (~.entity_type.GetEntityTypeRequest): + The request object. The request message for + [EntityTypes.GetEntityType][google.cloud.dialogflow.v2beta1.EntityTypes.GetEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.entity_type.EntityType: + Each intent parameter has a type, called the entity + type, which dictates exactly how data from an end-user + expression is extracted. + + Dialogflow provides predefined system entities that can + match many common types of data. For example, there are + system entities for matching dates, times, colors, email + addresses, and so on. You can also create your own + custom entities for matching custom data. For example, + you could define a vegetable entity that can match the + types of vegetables available for purchase with a + grocery store agent. + + For more information, see the `Entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/agent/entityTypes/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_get_entity_type(request, metadata) + pb_request = entity_type.GetEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = entity_type.EntityType() + pb_resp = entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_entity_type(resp) + return resp + + class _ListEntityTypes(EntityTypesRestStub): + def __hash__(self): + return hash("ListEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: entity_type.ListEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> entity_type.ListEntityTypesResponse: + r"""Call the list entity types method over HTTP. + + Args: + request (~.entity_type.ListEntityTypesRequest): + The request object. The request message for + [EntityTypes.ListEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.ListEntityTypes]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.entity_type.ListEntityTypesResponse: + The response message for + [EntityTypes.ListEntityTypes][google.cloud.dialogflow.v2beta1.EntityTypes.ListEntityTypes]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent}/entityTypes", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/entityTypes", + }, + ] + request, metadata = self._interceptor.pre_list_entity_types( + request, metadata + ) + pb_request = entity_type.ListEntityTypesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = entity_type.ListEntityTypesResponse() + pb_resp = entity_type.ListEntityTypesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_entity_types(resp) + return resp + + class _UpdateEntityType(EntityTypesRestStub): + def __hash__(self): + return hash("UpdateEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_entity_type.UpdateEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_entity_type.EntityType: + r"""Call the update entity type method over HTTP. + + Args: + request (~.gcd_entity_type.UpdateEntityTypeRequest): + The request object. The request message for + [EntityTypes.UpdateEntityType][google.cloud.dialogflow.v2beta1.EntityTypes.UpdateEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_entity_type.EntityType: + Each intent parameter has a type, called the entity + type, which dictates exactly how data from an end-user + expression is extracted. + + Dialogflow provides predefined system entities that can + match many common types of data. For example, there are + system entities for matching dates, times, colors, email + addresses, and so on. You can also create your own + custom entities for matching custom data. For example, + you could define a vegetable entity that can match the + types of vegetables available for purchase with a + grocery store agent. + + For more information, see the `Entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{entity_type.name=projects/*/agent/entityTypes/*}", + "body": "entity_type", + }, + { + "method": "patch", + "uri": "/v2beta1/{entity_type.name=projects/*/locations/*/agent/entityTypes/*}", + "body": "entity_type", + }, + ] + request, metadata = self._interceptor.pre_update_entity_type( + request, metadata + ) + pb_request = gcd_entity_type.UpdateEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_entity_type.EntityType() + pb_resp = gcd_entity_type.EntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_entity_type(resp) + return resp + + @property + def batch_create_entities( + self, + ) -> Callable[[entity_type.BatchCreateEntitiesRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchCreateEntities(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_delete_entities( + self, + ) -> Callable[[entity_type.BatchDeleteEntitiesRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchDeleteEntities(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_delete_entity_types( + self, + ) -> Callable[ + [entity_type.BatchDeleteEntityTypesRequest], operations_pb2.Operation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchDeleteEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_update_entities( + self, + ) -> Callable[[entity_type.BatchUpdateEntitiesRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchUpdateEntities(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_update_entity_types( + self, + ) -> Callable[ + [entity_type.BatchUpdateEntityTypesRequest], operations_pb2.Operation + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchUpdateEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_entity_type( + self, + ) -> Callable[ + [gcd_entity_type.CreateEntityTypeRequest], gcd_entity_type.EntityType + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_entity_type( + self, + ) -> Callable[[entity_type.DeleteEntityTypeRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_entity_type( + self, + ) -> Callable[[entity_type.GetEntityTypeRequest], entity_type.EntityType]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_entity_types( + self, + ) -> Callable[ + [entity_type.ListEntityTypesRequest], entity_type.ListEntityTypesResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_entity_type( + self, + ) -> Callable[ + [gcd_entity_type.UpdateEntityTypeRequest], gcd_entity_type.EntityType + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(EntityTypesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(EntityTypesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(EntityTypesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(EntityTypesRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(EntityTypesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("EntityTypesRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/environments/client.py b/google/cloud/dialogflow_v2beta1/services/environments/client.py index 5044d3518..295b4dd09 100644 --- a/google/cloud/dialogflow_v2beta1/services/environments/client.py +++ b/google/cloud/dialogflow_v2beta1/services/environments/client.py @@ -56,6 +56,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, EnvironmentsTransport from .transports.grpc import EnvironmentsGrpcTransport from .transports.grpc_asyncio import EnvironmentsGrpcAsyncIOTransport +from .transports.rest import EnvironmentsRestTransport class EnvironmentsClientMeta(type): @@ -69,6 +70,7 @@ class EnvironmentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[EnvironmentsTransport]] _transport_registry["grpc"] = EnvironmentsGrpcTransport _transport_registry["grpc_asyncio"] = EnvironmentsGrpcAsyncIOTransport + _transport_registry["rest"] = EnvironmentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/environments/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/environments/transports/__init__.py index abc173bb4..f8e2a8257 100644 --- a/google/cloud/dialogflow_v2beta1/services/environments/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/environments/transports/__init__.py @@ -19,14 +19,18 @@ from .base import EnvironmentsTransport from .grpc import EnvironmentsGrpcTransport from .grpc_asyncio import EnvironmentsGrpcAsyncIOTransport +from .rest import EnvironmentsRestInterceptor, EnvironmentsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[EnvironmentsTransport]] _transport_registry["grpc"] = EnvironmentsGrpcTransport _transport_registry["grpc_asyncio"] = EnvironmentsGrpcAsyncIOTransport +_transport_registry["rest"] = EnvironmentsRestTransport __all__ = ( "EnvironmentsTransport", "EnvironmentsGrpcTransport", "EnvironmentsGrpcAsyncIOTransport", + "EnvironmentsRestTransport", + "EnvironmentsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/environments/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/environments/transports/rest.py new file mode 100644 index 000000000..5b1c14391 --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/environments/transports/rest.py @@ -0,0 +1,1496 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2beta1.types import environment + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import EnvironmentsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class EnvironmentsRestInterceptor: + """Interceptor for Environments. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the EnvironmentsRestTransport. + + .. code-block:: python + class MyCustomEnvironmentsInterceptor(EnvironmentsRestInterceptor): + def pre_create_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_environment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_environment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_environment_history(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_environment_history(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_environments(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_environments(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_environment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_environment(self, response): + logging.log(f"Received response: {response}") + return response + + transport = EnvironmentsRestTransport(interceptor=MyCustomEnvironmentsInterceptor()) + client = EnvironmentsClient(transport=transport) + + + """ + + def pre_create_environment( + self, + request: environment.CreateEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.CreateEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_create_environment( + self, response: environment.Environment + ) -> environment.Environment: + """Post-rpc interceptor for create_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_delete_environment( + self, + request: environment.DeleteEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.DeleteEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def pre_get_environment( + self, + request: environment.GetEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.GetEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_environment( + self, response: environment.Environment + ) -> environment.Environment: + """Post-rpc interceptor for get_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_get_environment_history( + self, + request: environment.GetEnvironmentHistoryRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.GetEnvironmentHistoryRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_environment_history + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_environment_history( + self, response: environment.EnvironmentHistory + ) -> environment.EnvironmentHistory: + """Post-rpc interceptor for get_environment_history + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_environments( + self, + request: environment.ListEnvironmentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.ListEnvironmentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_environments + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_environments( + self, response: environment.ListEnvironmentsResponse + ) -> environment.ListEnvironmentsResponse: + """Post-rpc interceptor for list_environments + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_update_environment( + self, + request: environment.UpdateEnvironmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[environment.UpdateEnvironmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_environment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_update_environment( + self, response: environment.Environment + ) -> environment.Environment: + """Post-rpc interceptor for update_environment + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Environments server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Environments server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class EnvironmentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: EnvironmentsRestInterceptor + + +class EnvironmentsRestTransport(EnvironmentsTransport): + """REST backend transport for Environments. + + Service for managing + [Environments][google.cloud.dialogflow.v2beta1.Environment]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[EnvironmentsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or EnvironmentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("CreateEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "environmentId": "", + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.CreateEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.Environment: + r"""Call the create environment method over HTTP. + + Args: + request (~.environment.CreateEnvironmentRequest): + The request object. The request message for + [Environments.CreateEnvironment][google.cloud.dialogflow.v2beta1.Environments.CreateEnvironment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.environment.Environment: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent}/environments", + "body": "environment", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/environments", + "body": "environment", + }, + ] + request, metadata = self._interceptor.pre_create_environment( + request, metadata + ) + pb_request = environment.CreateEnvironmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = environment.Environment() + pb_resp = environment.Environment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_environment(resp) + return resp + + class _DeleteEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("DeleteEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.DeleteEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete environment method over HTTP. + + Args: + request (~.environment.DeleteEnvironmentRequest): + The request object. The request message for + [Environments.DeleteEnvironment][google.cloud.dialogflow.v2beta1.Environments.DeleteEnvironment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/agent/environments/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/environments/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_environment( + request, metadata + ) + pb_request = environment.DeleteEnvironmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("GetEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.GetEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.Environment: + r"""Call the get environment method over HTTP. + + Args: + request (~.environment.GetEnvironmentRequest): + The request object. The request message for + [Environments.GetEnvironment][google.cloud.dialogflow.v2beta1.Environments.GetEnvironment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.environment.Environment: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/agent/environments/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/environments/*}", + }, + ] + request, metadata = self._interceptor.pre_get_environment(request, metadata) + pb_request = environment.GetEnvironmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = environment.Environment() + pb_resp = environment.Environment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_environment(resp) + return resp + + class _GetEnvironmentHistory(EnvironmentsRestStub): + def __hash__(self): + return hash("GetEnvironmentHistory") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.GetEnvironmentHistoryRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.EnvironmentHistory: + r"""Call the get environment history method over HTTP. + + Args: + request (~.environment.GetEnvironmentHistoryRequest): + The request object. The request message for + [Environments.GetEnvironmentHistory][google.cloud.dialogflow.v2beta1.Environments.GetEnvironmentHistory]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.environment.EnvironmentHistory: + The response message for + [Environments.GetEnvironmentHistory][google.cloud.dialogflow.v2beta1.Environments.GetEnvironmentHistory]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent/environments/*}/history", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/environments/*}/history", + }, + ] + request, metadata = self._interceptor.pre_get_environment_history( + request, metadata + ) + pb_request = environment.GetEnvironmentHistoryRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = environment.EnvironmentHistory() + pb_resp = environment.EnvironmentHistory.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_environment_history(resp) + return resp + + class _ListEnvironments(EnvironmentsRestStub): + def __hash__(self): + return hash("ListEnvironments") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.ListEnvironmentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.ListEnvironmentsResponse: + r"""Call the list environments method over HTTP. + + Args: + request (~.environment.ListEnvironmentsRequest): + The request object. The request message for + [Environments.ListEnvironments][google.cloud.dialogflow.v2beta1.Environments.ListEnvironments]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.environment.ListEnvironmentsResponse: + The response message for + [Environments.ListEnvironments][google.cloud.dialogflow.v2beta1.Environments.ListEnvironments]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent}/environments", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/environments", + }, + ] + request, metadata = self._interceptor.pre_list_environments( + request, metadata + ) + pb_request = environment.ListEnvironmentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = environment.ListEnvironmentsResponse() + pb_resp = environment.ListEnvironmentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_environments(resp) + return resp + + class _UpdateEnvironment(EnvironmentsRestStub): + def __hash__(self): + return hash("UpdateEnvironment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: environment.UpdateEnvironmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> environment.Environment: + r"""Call the update environment method over HTTP. + + Args: + request (~.environment.UpdateEnvironmentRequest): + The request object. The request message for + [Environments.UpdateEnvironment][google.cloud.dialogflow.v2beta1.Environments.UpdateEnvironment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.environment.Environment: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{environment.name=projects/*/agent/environments/*}", + "body": "environment", + }, + { + "method": "patch", + "uri": "/v2beta1/{environment.name=projects/*/locations/*/agent/environments/*}", + "body": "environment", + }, + ] + request, metadata = self._interceptor.pre_update_environment( + request, metadata + ) + pb_request = environment.UpdateEnvironmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = environment.Environment() + pb_resp = environment.Environment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_environment(resp) + return resp + + @property + def create_environment( + self, + ) -> Callable[[environment.CreateEnvironmentRequest], environment.Environment]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_environment( + self, + ) -> Callable[[environment.DeleteEnvironmentRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_environment( + self, + ) -> Callable[[environment.GetEnvironmentRequest], environment.Environment]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_environment_history( + self, + ) -> Callable[ + [environment.GetEnvironmentHistoryRequest], environment.EnvironmentHistory + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetEnvironmentHistory(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_environments( + self, + ) -> Callable[ + [environment.ListEnvironmentsRequest], environment.ListEnvironmentsResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListEnvironments(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_environment( + self, + ) -> Callable[[environment.UpdateEnvironmentRequest], environment.Environment]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateEnvironment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(EnvironmentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(EnvironmentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(EnvironmentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(EnvironmentsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(EnvironmentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("EnvironmentsRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/fulfillments/client.py b/google/cloud/dialogflow_v2beta1/services/fulfillments/client.py index bd4f297bc..cf27f054b 100644 --- a/google/cloud/dialogflow_v2beta1/services/fulfillments/client.py +++ b/google/cloud/dialogflow_v2beta1/services/fulfillments/client.py @@ -56,6 +56,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, FulfillmentsTransport from .transports.grpc import FulfillmentsGrpcTransport from .transports.grpc_asyncio import FulfillmentsGrpcAsyncIOTransport +from .transports.rest import FulfillmentsRestTransport class FulfillmentsClientMeta(type): @@ -69,6 +70,7 @@ class FulfillmentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[FulfillmentsTransport]] _transport_registry["grpc"] = FulfillmentsGrpcTransport _transport_registry["grpc_asyncio"] = FulfillmentsGrpcAsyncIOTransport + _transport_registry["rest"] = FulfillmentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/fulfillments/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/fulfillments/transports/__init__.py index e3a19cdc3..b2f6ffd50 100644 --- a/google/cloud/dialogflow_v2beta1/services/fulfillments/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/fulfillments/transports/__init__.py @@ -19,14 +19,18 @@ from .base import FulfillmentsTransport from .grpc import FulfillmentsGrpcTransport from .grpc_asyncio import FulfillmentsGrpcAsyncIOTransport +from .rest import FulfillmentsRestInterceptor, FulfillmentsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[FulfillmentsTransport]] _transport_registry["grpc"] = FulfillmentsGrpcTransport _transport_registry["grpc_asyncio"] = FulfillmentsGrpcAsyncIOTransport +_transport_registry["rest"] = FulfillmentsRestTransport __all__ = ( "FulfillmentsTransport", "FulfillmentsGrpcTransport", "FulfillmentsGrpcAsyncIOTransport", + "FulfillmentsRestTransport", + "FulfillmentsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/fulfillments/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/fulfillments/transports/rest.py new file mode 100644 index 000000000..b06d6244b --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/fulfillments/transports/rest.py @@ -0,0 +1,939 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.dialogflow_v2beta1.types import fulfillment as gcd_fulfillment +from google.cloud.dialogflow_v2beta1.types import fulfillment + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import FulfillmentsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class FulfillmentsRestInterceptor: + """Interceptor for Fulfillments. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the FulfillmentsRestTransport. + + .. code-block:: python + class MyCustomFulfillmentsInterceptor(FulfillmentsRestInterceptor): + def pre_get_fulfillment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_fulfillment(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_fulfillment(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_fulfillment(self, response): + logging.log(f"Received response: {response}") + return response + + transport = FulfillmentsRestTransport(interceptor=MyCustomFulfillmentsInterceptor()) + client = FulfillmentsClient(transport=transport) + + + """ + + def pre_get_fulfillment( + self, + request: fulfillment.GetFulfillmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[fulfillment.GetFulfillmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_fulfillment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_get_fulfillment( + self, response: fulfillment.Fulfillment + ) -> fulfillment.Fulfillment: + """Post-rpc interceptor for get_fulfillment + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_update_fulfillment( + self, + request: gcd_fulfillment.UpdateFulfillmentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_fulfillment.UpdateFulfillmentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_fulfillment + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_update_fulfillment( + self, response: gcd_fulfillment.Fulfillment + ) -> gcd_fulfillment.Fulfillment: + """Post-rpc interceptor for update_fulfillment + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Fulfillments server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Fulfillments server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class FulfillmentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: FulfillmentsRestInterceptor + + +class FulfillmentsRestTransport(FulfillmentsTransport): + """REST backend transport for Fulfillments. + + Service for managing + [Fulfillments][google.cloud.dialogflow.v2beta1.Fulfillment]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[FulfillmentsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or FulfillmentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _GetFulfillment(FulfillmentsRestStub): + def __hash__(self): + return hash("GetFulfillment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: fulfillment.GetFulfillmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> fulfillment.Fulfillment: + r"""Call the get fulfillment method over HTTP. + + Args: + request (~.fulfillment.GetFulfillmentRequest): + The request object. The request message for + [Fulfillments.GetFulfillment][google.cloud.dialogflow.v2beta1.Fulfillments.GetFulfillment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.fulfillment.Fulfillment: + By default, your agent responds to a matched intent with + a static response. As an alternative, you can provide a + more dynamic response by using fulfillment. When you + enable fulfillment for an intent, Dialogflow responds to + that intent by calling a service that you define. For + example, if an end-user wants to schedule a haircut on + Friday, your service can check your database and respond + to the end-user with availability information for + Friday. + + For more information, see the `fulfillment + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/agent/fulfillment}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/fulfillment}", + }, + ] + request, metadata = self._interceptor.pre_get_fulfillment(request, metadata) + pb_request = fulfillment.GetFulfillmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = fulfillment.Fulfillment() + pb_resp = fulfillment.Fulfillment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_fulfillment(resp) + return resp + + class _UpdateFulfillment(FulfillmentsRestStub): + def __hash__(self): + return hash("UpdateFulfillment") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_fulfillment.UpdateFulfillmentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_fulfillment.Fulfillment: + r"""Call the update fulfillment method over HTTP. + + Args: + request (~.gcd_fulfillment.UpdateFulfillmentRequest): + The request object. The request message for + [Fulfillments.UpdateFulfillment][google.cloud.dialogflow.v2beta1.Fulfillments.UpdateFulfillment]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_fulfillment.Fulfillment: + By default, your agent responds to a matched intent with + a static response. As an alternative, you can provide a + more dynamic response by using fulfillment. When you + enable fulfillment for an intent, Dialogflow responds to + that intent by calling a service that you define. For + example, if an end-user wants to schedule a haircut on + Friday, your service can check your database and respond + to the end-user with availability information for + Friday. + + For more information, see the `fulfillment + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{fulfillment.name=projects/*/agent/fulfillment}", + "body": "fulfillment", + }, + { + "method": "patch", + "uri": "/v2beta1/{fulfillment.name=projects/*/locations/*/agent/fulfillment}", + "body": "fulfillment", + }, + ] + request, metadata = self._interceptor.pre_update_fulfillment( + request, metadata + ) + pb_request = gcd_fulfillment.UpdateFulfillmentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_fulfillment.Fulfillment() + pb_resp = gcd_fulfillment.Fulfillment.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_fulfillment(resp) + return resp + + @property + def get_fulfillment( + self, + ) -> Callable[[fulfillment.GetFulfillmentRequest], fulfillment.Fulfillment]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetFulfillment(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_fulfillment( + self, + ) -> Callable[ + [gcd_fulfillment.UpdateFulfillmentRequest], gcd_fulfillment.Fulfillment + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateFulfillment(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(FulfillmentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(FulfillmentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(FulfillmentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(FulfillmentsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(FulfillmentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("FulfillmentsRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/intents/client.py b/google/cloud/dialogflow_v2beta1/services/intents/client.py index 771cabead..2966f4fa9 100644 --- a/google/cloud/dialogflow_v2beta1/services/intents/client.py +++ b/google/cloud/dialogflow_v2beta1/services/intents/client.py @@ -62,6 +62,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, IntentsTransport from .transports.grpc import IntentsGrpcTransport from .transports.grpc_asyncio import IntentsGrpcAsyncIOTransport +from .transports.rest import IntentsRestTransport class IntentsClientMeta(type): @@ -75,6 +76,7 @@ class IntentsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[IntentsTransport]] _transport_registry["grpc"] = IntentsGrpcTransport _transport_registry["grpc_asyncio"] = IntentsGrpcAsyncIOTransport + _transport_registry["rest"] = IntentsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/intents/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/intents/transports/__init__.py index a325bcd97..794b2f132 100644 --- a/google/cloud/dialogflow_v2beta1/services/intents/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/intents/transports/__init__.py @@ -19,14 +19,18 @@ from .base import IntentsTransport from .grpc import IntentsGrpcTransport from .grpc_asyncio import IntentsGrpcAsyncIOTransport +from .rest import IntentsRestInterceptor, IntentsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[IntentsTransport]] _transport_registry["grpc"] = IntentsGrpcTransport _transport_registry["grpc_asyncio"] = IntentsGrpcAsyncIOTransport +_transport_registry["rest"] = IntentsRestTransport __all__ = ( "IntentsTransport", "IntentsGrpcTransport", "IntentsGrpcAsyncIOTransport", + "IntentsRestTransport", + "IntentsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/intents/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/intents/transports/rest.py new file mode 100644 index 000000000..8b98c7f15 --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/intents/transports/rest.py @@ -0,0 +1,1668 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import ( + gapic_v1, + operations_v1, + path_template, + rest_helpers, + rest_streaming, +) +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2beta1.types import intent +from google.cloud.dialogflow_v2beta1.types import intent as gcd_intent + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import IntentsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class IntentsRestInterceptor: + """Interceptor for Intents. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the IntentsRestTransport. + + .. code-block:: python + class MyCustomIntentsInterceptor(IntentsRestInterceptor): + def pre_batch_delete_intents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_delete_intents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_batch_update_intents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_batch_update_intents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_intent(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_intents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_intents(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_intent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = IntentsRestTransport(interceptor=MyCustomIntentsInterceptor()) + client = IntentsClient(transport=transport) + + + """ + + def pre_batch_delete_intents( + self, + request: intent.BatchDeleteIntentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[intent.BatchDeleteIntentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_delete_intents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_batch_delete_intents( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_delete_intents + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_batch_update_intents( + self, + request: intent.BatchUpdateIntentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[intent.BatchUpdateIntentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for batch_update_intents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_batch_update_intents( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for batch_update_intents + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_create_intent( + self, + request: gcd_intent.CreateIntentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_intent.CreateIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_create_intent(self, response: gcd_intent.Intent) -> gcd_intent.Intent: + """Post-rpc interceptor for create_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_delete_intent( + self, request: intent.DeleteIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.DeleteIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def pre_get_intent( + self, request: intent.GetIntentRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.GetIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_intent(self, response: intent.Intent) -> intent.Intent: + """Post-rpc interceptor for get_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_intents( + self, request: intent.ListIntentsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[intent.ListIntentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_intents + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_intents( + self, response: intent.ListIntentsResponse + ) -> intent.ListIntentsResponse: + """Post-rpc interceptor for list_intents + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_update_intent( + self, + request: gcd_intent.UpdateIntentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_intent.UpdateIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_update_intent(self, response: gcd_intent.Intent) -> gcd_intent.Intent: + """Post-rpc interceptor for update_intent + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Intents server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Intents server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class IntentsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: IntentsRestInterceptor + + +class IntentsRestTransport(IntentsTransport): + """REST backend transport for Intents. + + Service for managing + [Intents][google.cloud.dialogflow.v2beta1.Intent]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[IntentsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + self._operations_client: Optional[operations_v1.AbstractOperationsClient] = None + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or IntentsRestInterceptor() + self._prep_wrapped_messages(client_info) + + @property + def operations_client(self) -> operations_v1.AbstractOperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Only create a new client if we do not already have one. + if self._operations_client is None: + http_options: Dict[str, List[Dict[str, str]]] = { + "google.longrunning.Operations.CancelOperation": [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ], + "google.longrunning.Operations.GetOperation": [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ], + "google.longrunning.Operations.ListOperations": [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ], + } + + rest_transport = operations_v1.OperationsRestTransport( + host=self._host, + # use the credentials which are saved + credentials=self._credentials, + scopes=self._scopes, + http_options=http_options, + path_prefix="v2beta1", + ) + + self._operations_client = operations_v1.AbstractOperationsClient( + transport=rest_transport + ) + + # Return the client from cache. + return self._operations_client + + class _BatchDeleteIntents(IntentsRestStub): + def __hash__(self): + return hash("BatchDeleteIntents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: intent.BatchDeleteIntentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch delete intents method over HTTP. + + Args: + request (~.intent.BatchDeleteIntentsRequest): + The request object. The request message for + [Intents.BatchDeleteIntents][google.cloud.dialogflow.v2beta1.Intents.BatchDeleteIntents]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent}/intents:batchDelete", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/intents:batchDelete", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_delete_intents( + request, metadata + ) + pb_request = intent.BatchDeleteIntentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_delete_intents(resp) + return resp + + class _BatchUpdateIntents(IntentsRestStub): + def __hash__(self): + return hash("BatchUpdateIntents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: intent.BatchUpdateIntentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the batch update intents method over HTTP. + + Args: + request (~.intent.BatchUpdateIntentsRequest): + The request object. The request message for + [Intents.BatchUpdateIntents][google.cloud.dialogflow.v2beta1.Intents.BatchUpdateIntents]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent}/intents:batchUpdate", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/intents:batchUpdate", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_batch_update_intents( + request, metadata + ) + pb_request = intent.BatchUpdateIntentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + resp = self._interceptor.post_batch_update_intents(resp) + return resp + + class _CreateIntent(IntentsRestStub): + def __hash__(self): + return hash("CreateIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_intent.CreateIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_intent.Intent: + r"""Call the create intent method over HTTP. + + Args: + request (~.gcd_intent.CreateIntentRequest): + The request object. The request message for + [Intents.CreateIntent][google.cloud.dialogflow.v2beta1.Intents.CreateIntent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_intent.Intent: + An intent categorizes an end-user's intention for one + conversation turn. For each agent, you define many + intents, where your combined intents can handle a + complete conversation. When an end-user writes or says + something, referred to as an end-user expression or + end-user input, Dialogflow matches the end-user input to + the best intent in your agent. Matching an intent is + also known as intent classification. + + For more information, see the `intent + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent}/intents", + "body": "intent", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/intents", + "body": "intent", + }, + ] + request, metadata = self._interceptor.pre_create_intent(request, metadata) + pb_request = gcd_intent.CreateIntentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_intent.Intent() + pb_resp = gcd_intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_intent(resp) + return resp + + class _DeleteIntent(IntentsRestStub): + def __hash__(self): + return hash("DeleteIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: intent.DeleteIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete intent method over HTTP. + + Args: + request (~.intent.DeleteIntentRequest): + The request object. The request message for + [Intents.DeleteIntent][google.cloud.dialogflow.v2beta1.Intents.DeleteIntent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/agent/intents/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/intents/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_intent(request, metadata) + pb_request = intent.DeleteIntentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetIntent(IntentsRestStub): + def __hash__(self): + return hash("GetIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: intent.GetIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> intent.Intent: + r"""Call the get intent method over HTTP. + + Args: + request (~.intent.GetIntentRequest): + The request object. The request message for + [Intents.GetIntent][google.cloud.dialogflow.v2beta1.Intents.GetIntent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.intent.Intent: + An intent categorizes an end-user's intention for one + conversation turn. For each agent, you define many + intents, where your combined intents can handle a + complete conversation. When an end-user writes or says + something, referred to as an end-user expression or + end-user input, Dialogflow matches the end-user input to + the best intent in your agent. Matching an intent is + also known as intent classification. + + For more information, see the `intent + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/agent/intents/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/intents/*}", + }, + ] + request, metadata = self._interceptor.pre_get_intent(request, metadata) + pb_request = intent.GetIntentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = intent.Intent() + pb_resp = intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_intent(resp) + return resp + + class _ListIntents(IntentsRestStub): + def __hash__(self): + return hash("ListIntents") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: intent.ListIntentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> intent.ListIntentsResponse: + r"""Call the list intents method over HTTP. + + Args: + request (~.intent.ListIntentsRequest): + The request object. The request message for + [Intents.ListIntents][google.cloud.dialogflow.v2beta1.Intents.ListIntents]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.intent.ListIntentsResponse: + The response message for + [Intents.ListIntents][google.cloud.dialogflow.v2beta1.Intents.ListIntents]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent}/intents", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/intents", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent/environments/*}/intents", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/environments/*}/intents", + }, + ] + request, metadata = self._interceptor.pre_list_intents(request, metadata) + pb_request = intent.ListIntentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = intent.ListIntentsResponse() + pb_resp = intent.ListIntentsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_intents(resp) + return resp + + class _UpdateIntent(IntentsRestStub): + def __hash__(self): + return hash("UpdateIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_intent.UpdateIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_intent.Intent: + r"""Call the update intent method over HTTP. + + Args: + request (~.gcd_intent.UpdateIntentRequest): + The request object. The request message for + [Intents.UpdateIntent][google.cloud.dialogflow.v2beta1.Intents.UpdateIntent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_intent.Intent: + An intent categorizes an end-user's intention for one + conversation turn. For each agent, you define many + intents, where your combined intents can handle a + complete conversation. When an end-user writes or says + something, referred to as an end-user expression or + end-user input, Dialogflow matches the end-user input to + the best intent in your agent. Matching an intent is + also known as intent classification. + + For more information, see the `intent + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{intent.name=projects/*/agent/intents/*}", + "body": "intent", + }, + { + "method": "patch", + "uri": "/v2beta1/{intent.name=projects/*/locations/*/agent/intents/*}", + "body": "intent", + }, + ] + request, metadata = self._interceptor.pre_update_intent(request, metadata) + pb_request = gcd_intent.UpdateIntentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_intent.Intent() + pb_resp = gcd_intent.Intent.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_intent(resp) + return resp + + @property + def batch_delete_intents( + self, + ) -> Callable[[intent.BatchDeleteIntentsRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchDeleteIntents(self._session, self._host, self._interceptor) # type: ignore + + @property + def batch_update_intents( + self, + ) -> Callable[[intent.BatchUpdateIntentsRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._BatchUpdateIntents(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_intent( + self, + ) -> Callable[[gcd_intent.CreateIntentRequest], gcd_intent.Intent]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_intent(self) -> Callable[[intent.DeleteIntentRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_intent(self) -> Callable[[intent.GetIntentRequest], intent.Intent]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_intents( + self, + ) -> Callable[[intent.ListIntentsRequest], intent.ListIntentsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListIntents(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_intent( + self, + ) -> Callable[[gcd_intent.UpdateIntentRequest], gcd_intent.Intent]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(IntentsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(IntentsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(IntentsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(IntentsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(IntentsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("IntentsRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/knowledge_bases/client.py b/google/cloud/dialogflow_v2beta1/services/knowledge_bases/client.py index b90ba932e..b568bf63d 100644 --- a/google/cloud/dialogflow_v2beta1/services/knowledge_bases/client.py +++ b/google/cloud/dialogflow_v2beta1/services/knowledge_bases/client.py @@ -57,6 +57,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, KnowledgeBasesTransport from .transports.grpc import KnowledgeBasesGrpcTransport from .transports.grpc_asyncio import KnowledgeBasesGrpcAsyncIOTransport +from .transports.rest import KnowledgeBasesRestTransport class KnowledgeBasesClientMeta(type): @@ -72,6 +73,7 @@ class KnowledgeBasesClientMeta(type): ) # type: Dict[str, Type[KnowledgeBasesTransport]] _transport_registry["grpc"] = KnowledgeBasesGrpcTransport _transport_registry["grpc_asyncio"] = KnowledgeBasesGrpcAsyncIOTransport + _transport_registry["rest"] = KnowledgeBasesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/knowledge_bases/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/knowledge_bases/transports/__init__.py index be23a741a..285b76dcb 100644 --- a/google/cloud/dialogflow_v2beta1/services/knowledge_bases/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/knowledge_bases/transports/__init__.py @@ -19,14 +19,18 @@ from .base import KnowledgeBasesTransport from .grpc import KnowledgeBasesGrpcTransport from .grpc_asyncio import KnowledgeBasesGrpcAsyncIOTransport +from .rest import KnowledgeBasesRestInterceptor, KnowledgeBasesRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[KnowledgeBasesTransport]] _transport_registry["grpc"] = KnowledgeBasesGrpcTransport _transport_registry["grpc_asyncio"] = KnowledgeBasesGrpcAsyncIOTransport +_transport_registry["rest"] = KnowledgeBasesRestTransport __all__ = ( "KnowledgeBasesTransport", "KnowledgeBasesGrpcTransport", "KnowledgeBasesGrpcAsyncIOTransport", + "KnowledgeBasesRestTransport", + "KnowledgeBasesRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/knowledge_bases/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/knowledge_bases/transports/rest.py new file mode 100644 index 000000000..02ddb3db2 --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/knowledge_bases/transports/rest.py @@ -0,0 +1,1372 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2beta1.types import knowledge_base as gcd_knowledge_base +from google.cloud.dialogflow_v2beta1.types import knowledge_base + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import KnowledgeBasesTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class KnowledgeBasesRestInterceptor: + """Interceptor for KnowledgeBases. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the KnowledgeBasesRestTransport. + + .. code-block:: python + class MyCustomKnowledgeBasesInterceptor(KnowledgeBasesRestInterceptor): + def pre_create_knowledge_base(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_knowledge_base(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_knowledge_base(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_knowledge_base(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_knowledge_base(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_knowledge_bases(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_knowledge_bases(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_knowledge_base(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_knowledge_base(self, response): + logging.log(f"Received response: {response}") + return response + + transport = KnowledgeBasesRestTransport(interceptor=MyCustomKnowledgeBasesInterceptor()) + client = KnowledgeBasesClient(transport=transport) + + + """ + + def pre_create_knowledge_base( + self, + request: gcd_knowledge_base.CreateKnowledgeBaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_knowledge_base.CreateKnowledgeBaseRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for create_knowledge_base + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_create_knowledge_base( + self, response: gcd_knowledge_base.KnowledgeBase + ) -> gcd_knowledge_base.KnowledgeBase: + """Post-rpc interceptor for create_knowledge_base + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_delete_knowledge_base( + self, + request: knowledge_base.DeleteKnowledgeBaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[knowledge_base.DeleteKnowledgeBaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_knowledge_base + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def pre_get_knowledge_base( + self, + request: knowledge_base.GetKnowledgeBaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[knowledge_base.GetKnowledgeBaseRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_knowledge_base + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_get_knowledge_base( + self, response: knowledge_base.KnowledgeBase + ) -> knowledge_base.KnowledgeBase: + """Post-rpc interceptor for get_knowledge_base + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_list_knowledge_bases( + self, + request: knowledge_base.ListKnowledgeBasesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[knowledge_base.ListKnowledgeBasesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_knowledge_bases + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_list_knowledge_bases( + self, response: knowledge_base.ListKnowledgeBasesResponse + ) -> knowledge_base.ListKnowledgeBasesResponse: + """Post-rpc interceptor for list_knowledge_bases + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_update_knowledge_base( + self, + request: gcd_knowledge_base.UpdateKnowledgeBaseRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_knowledge_base.UpdateKnowledgeBaseRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for update_knowledge_base + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_update_knowledge_base( + self, response: gcd_knowledge_base.KnowledgeBase + ) -> gcd_knowledge_base.KnowledgeBase: + """Post-rpc interceptor for update_knowledge_base + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the KnowledgeBases server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the KnowledgeBases server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class KnowledgeBasesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: KnowledgeBasesRestInterceptor + + +class KnowledgeBasesRestTransport(KnowledgeBasesTransport): + """REST backend transport for KnowledgeBases. + + Service for managing + [KnowledgeBases][google.cloud.dialogflow.v2beta1.KnowledgeBase]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[KnowledgeBasesRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or KnowledgeBasesRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateKnowledgeBase(KnowledgeBasesRestStub): + def __hash__(self): + return hash("CreateKnowledgeBase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_knowledge_base.CreateKnowledgeBaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_knowledge_base.KnowledgeBase: + r"""Call the create knowledge base method over HTTP. + + Args: + request (~.gcd_knowledge_base.CreateKnowledgeBaseRequest): + The request object. Request message for + [KnowledgeBases.CreateKnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBases.CreateKnowledgeBase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_knowledge_base.KnowledgeBase: + A knowledge base represents a collection of knowledge + documents that you provide to Dialogflow. Your knowledge + documents contain information that may be useful during + conversations with end-users. Some Dialogflow features + use knowledge bases when looking for a response to an + end-user input. + + For more information, see the `knowledge base + guide `__. + + Note: The ``projects.agent.knowledgeBases`` resource is + deprecated; only use ``projects.knowledgeBases``. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*}/knowledgeBases", + "body": "knowledge_base", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*}/knowledgeBases", + "body": "knowledge_base", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent}/knowledgeBases", + "body": "knowledge_base", + }, + ] + request, metadata = self._interceptor.pre_create_knowledge_base( + request, metadata + ) + pb_request = gcd_knowledge_base.CreateKnowledgeBaseRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_knowledge_base.KnowledgeBase() + pb_resp = gcd_knowledge_base.KnowledgeBase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_knowledge_base(resp) + return resp + + class _DeleteKnowledgeBase(KnowledgeBasesRestStub): + def __hash__(self): + return hash("DeleteKnowledgeBase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: knowledge_base.DeleteKnowledgeBaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete knowledge base method over HTTP. + + Args: + request (~.knowledge_base.DeleteKnowledgeBaseRequest): + The request object. Request message for + [KnowledgeBases.DeleteKnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBases.DeleteKnowledgeBase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/knowledgeBases/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/locations/*/knowledgeBases/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/agent/knowledgeBases/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_knowledge_base( + request, metadata + ) + pb_request = knowledge_base.DeleteKnowledgeBaseRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetKnowledgeBase(KnowledgeBasesRestStub): + def __hash__(self): + return hash("GetKnowledgeBase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: knowledge_base.GetKnowledgeBaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> knowledge_base.KnowledgeBase: + r"""Call the get knowledge base method over HTTP. + + Args: + request (~.knowledge_base.GetKnowledgeBaseRequest): + The request object. Request message for + [KnowledgeBases.GetKnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBases.GetKnowledgeBase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.knowledge_base.KnowledgeBase: + A knowledge base represents a collection of knowledge + documents that you provide to Dialogflow. Your knowledge + documents contain information that may be useful during + conversations with end-users. Some Dialogflow features + use knowledge bases when looking for a response to an + end-user input. + + For more information, see the `knowledge base + guide `__. + + Note: The ``projects.agent.knowledgeBases`` resource is + deprecated; only use ``projects.knowledgeBases``. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/knowledgeBases/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/knowledgeBases/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/agent/knowledgeBases/*}", + }, + ] + request, metadata = self._interceptor.pre_get_knowledge_base( + request, metadata + ) + pb_request = knowledge_base.GetKnowledgeBaseRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = knowledge_base.KnowledgeBase() + pb_resp = knowledge_base.KnowledgeBase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_knowledge_base(resp) + return resp + + class _ListKnowledgeBases(KnowledgeBasesRestStub): + def __hash__(self): + return hash("ListKnowledgeBases") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: knowledge_base.ListKnowledgeBasesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> knowledge_base.ListKnowledgeBasesResponse: + r"""Call the list knowledge bases method over HTTP. + + Args: + request (~.knowledge_base.ListKnowledgeBasesRequest): + The request object. Request message for + [KnowledgeBases.ListKnowledgeBases][google.cloud.dialogflow.v2beta1.KnowledgeBases.ListKnowledgeBases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.knowledge_base.ListKnowledgeBasesResponse: + Response message for + [KnowledgeBases.ListKnowledgeBases][google.cloud.dialogflow.v2beta1.KnowledgeBases.ListKnowledgeBases]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*}/knowledgeBases", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*}/knowledgeBases", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent}/knowledgeBases", + }, + ] + request, metadata = self._interceptor.pre_list_knowledge_bases( + request, metadata + ) + pb_request = knowledge_base.ListKnowledgeBasesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = knowledge_base.ListKnowledgeBasesResponse() + pb_resp = knowledge_base.ListKnowledgeBasesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_knowledge_bases(resp) + return resp + + class _UpdateKnowledgeBase(KnowledgeBasesRestStub): + def __hash__(self): + return hash("UpdateKnowledgeBase") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_knowledge_base.UpdateKnowledgeBaseRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_knowledge_base.KnowledgeBase: + r"""Call the update knowledge base method over HTTP. + + Args: + request (~.gcd_knowledge_base.UpdateKnowledgeBaseRequest): + The request object. Request message for + [KnowledgeBases.UpdateKnowledgeBase][google.cloud.dialogflow.v2beta1.KnowledgeBases.UpdateKnowledgeBase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_knowledge_base.KnowledgeBase: + A knowledge base represents a collection of knowledge + documents that you provide to Dialogflow. Your knowledge + documents contain information that may be useful during + conversations with end-users. Some Dialogflow features + use knowledge bases when looking for a response to an + end-user input. + + For more information, see the `knowledge base + guide `__. + + Note: The ``projects.agent.knowledgeBases`` resource is + deprecated; only use ``projects.knowledgeBases``. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{knowledge_base.name=projects/*/knowledgeBases/*}", + "body": "knowledge_base", + }, + { + "method": "patch", + "uri": "/v2beta1/{knowledge_base.name=projects/*/locations/*/knowledgeBases/*}", + "body": "knowledge_base", + }, + { + "method": "patch", + "uri": "/v2beta1/{knowledge_base.name=projects/*/agent/knowledgeBases/*}", + "body": "knowledge_base", + }, + ] + request, metadata = self._interceptor.pre_update_knowledge_base( + request, metadata + ) + pb_request = gcd_knowledge_base.UpdateKnowledgeBaseRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_knowledge_base.KnowledgeBase() + pb_resp = gcd_knowledge_base.KnowledgeBase.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_knowledge_base(resp) + return resp + + @property + def create_knowledge_base( + self, + ) -> Callable[ + [gcd_knowledge_base.CreateKnowledgeBaseRequest], + gcd_knowledge_base.KnowledgeBase, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateKnowledgeBase(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_knowledge_base( + self, + ) -> Callable[[knowledge_base.DeleteKnowledgeBaseRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteKnowledgeBase(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_knowledge_base( + self, + ) -> Callable[ + [knowledge_base.GetKnowledgeBaseRequest], knowledge_base.KnowledgeBase + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetKnowledgeBase(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_knowledge_bases( + self, + ) -> Callable[ + [knowledge_base.ListKnowledgeBasesRequest], + knowledge_base.ListKnowledgeBasesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListKnowledgeBases(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_knowledge_base( + self, + ) -> Callable[ + [gcd_knowledge_base.UpdateKnowledgeBaseRequest], + gcd_knowledge_base.KnowledgeBase, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateKnowledgeBase(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(KnowledgeBasesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(KnowledgeBasesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(KnowledgeBasesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(KnowledgeBasesRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(KnowledgeBasesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("KnowledgeBasesRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/participants/client.py b/google/cloud/dialogflow_v2beta1/services/participants/client.py index cf15ee264..29cbfa3fc 100644 --- a/google/cloud/dialogflow_v2beta1/services/participants/client.py +++ b/google/cloud/dialogflow_v2beta1/services/participants/client.py @@ -61,6 +61,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, ParticipantsTransport from .transports.grpc import ParticipantsGrpcTransport from .transports.grpc_asyncio import ParticipantsGrpcAsyncIOTransport +from .transports.rest import ParticipantsRestTransport class ParticipantsClientMeta(type): @@ -74,6 +75,7 @@ class ParticipantsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[ParticipantsTransport]] _transport_registry["grpc"] = ParticipantsGrpcTransport _transport_registry["grpc_asyncio"] = ParticipantsGrpcAsyncIOTransport + _transport_registry["rest"] = ParticipantsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/participants/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/participants/transports/__init__.py index 05e4f7615..393948ada 100644 --- a/google/cloud/dialogflow_v2beta1/services/participants/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/participants/transports/__init__.py @@ -19,14 +19,18 @@ from .base import ParticipantsTransport from .grpc import ParticipantsGrpcTransport from .grpc_asyncio import ParticipantsGrpcAsyncIOTransport +from .rest import ParticipantsRestInterceptor, ParticipantsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[ParticipantsTransport]] _transport_registry["grpc"] = ParticipantsGrpcTransport _transport_registry["grpc_asyncio"] = ParticipantsGrpcAsyncIOTransport +_transport_registry["rest"] = ParticipantsRestTransport __all__ = ( "ParticipantsTransport", "ParticipantsGrpcTransport", "ParticipantsGrpcAsyncIOTransport", + "ParticipantsRestTransport", + "ParticipantsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/participants/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/participants/transports/rest.py new file mode 100644 index 000000000..222c34671 --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/participants/transports/rest.py @@ -0,0 +1,2070 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.dialogflow_v2beta1.types import participant as gcd_participant +from google.cloud.dialogflow_v2beta1.types import participant + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import ParticipantsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class ParticipantsRestInterceptor: + """Interceptor for Participants. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the ParticipantsRestTransport. + + .. code-block:: python + class MyCustomParticipantsInterceptor(ParticipantsRestInterceptor): + def pre_analyze_content(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_analyze_content(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_compile_suggestion(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_compile_suggestion(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_create_participant(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_participant(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_get_participant(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_participant(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_participants(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_participants(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_suggestions(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_suggestions(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_suggest_articles(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_suggest_articles(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_suggest_faq_answers(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_suggest_faq_answers(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_suggest_smart_replies(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_suggest_smart_replies(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_participant(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_participant(self, response): + logging.log(f"Received response: {response}") + return response + + transport = ParticipantsRestTransport(interceptor=MyCustomParticipantsInterceptor()) + client = ParticipantsClient(transport=transport) + + + """ + + def pre_analyze_content( + self, + request: gcd_participant.AnalyzeContentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_participant.AnalyzeContentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for analyze_content + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_analyze_content( + self, response: gcd_participant.AnalyzeContentResponse + ) -> gcd_participant.AnalyzeContentResponse: + """Post-rpc interceptor for analyze_content + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_compile_suggestion( + self, + request: participant.CompileSuggestionRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.CompileSuggestionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for compile_suggestion + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_compile_suggestion( + self, response: participant.CompileSuggestionResponse + ) -> participant.CompileSuggestionResponse: + """Post-rpc interceptor for compile_suggestion + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_create_participant( + self, + request: gcd_participant.CreateParticipantRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_participant.CreateParticipantRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_participant + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_create_participant( + self, response: gcd_participant.Participant + ) -> gcd_participant.Participant: + """Post-rpc interceptor for create_participant + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_get_participant( + self, + request: participant.GetParticipantRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.GetParticipantRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_participant + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_get_participant( + self, response: participant.Participant + ) -> participant.Participant: + """Post-rpc interceptor for get_participant + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_list_participants( + self, + request: participant.ListParticipantsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.ListParticipantsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_participants + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_list_participants( + self, response: participant.ListParticipantsResponse + ) -> participant.ListParticipantsResponse: + """Post-rpc interceptor for list_participants + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_list_suggestions( + self, + request: participant.ListSuggestionsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.ListSuggestionsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_suggestions + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_list_suggestions( + self, response: participant.ListSuggestionsResponse + ) -> participant.ListSuggestionsResponse: + """Post-rpc interceptor for list_suggestions + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_suggest_articles( + self, + request: participant.SuggestArticlesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.SuggestArticlesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for suggest_articles + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_suggest_articles( + self, response: participant.SuggestArticlesResponse + ) -> participant.SuggestArticlesResponse: + """Post-rpc interceptor for suggest_articles + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_suggest_faq_answers( + self, + request: participant.SuggestFaqAnswersRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.SuggestFaqAnswersRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for suggest_faq_answers + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_suggest_faq_answers( + self, response: participant.SuggestFaqAnswersResponse + ) -> participant.SuggestFaqAnswersResponse: + """Post-rpc interceptor for suggest_faq_answers + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_suggest_smart_replies( + self, + request: participant.SuggestSmartRepliesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[participant.SuggestSmartRepliesRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for suggest_smart_replies + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_suggest_smart_replies( + self, response: participant.SuggestSmartRepliesResponse + ) -> participant.SuggestSmartRepliesResponse: + """Post-rpc interceptor for suggest_smart_replies + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_update_participant( + self, + request: gcd_participant.UpdateParticipantRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_participant.UpdateParticipantRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_participant + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_update_participant( + self, response: gcd_participant.Participant + ) -> gcd_participant.Participant: + """Post-rpc interceptor for update_participant + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Participants server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Participants server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class ParticipantsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: ParticipantsRestInterceptor + + +class ParticipantsRestTransport(ParticipantsTransport): + """REST backend transport for Participants. + + Service for managing + [Participants][google.cloud.dialogflow.v2beta1.Participant]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[ParticipantsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or ParticipantsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _AnalyzeContent(ParticipantsRestStub): + def __hash__(self): + return hash("AnalyzeContent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_participant.AnalyzeContentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_participant.AnalyzeContentResponse: + r"""Call the analyze content method over HTTP. + + Args: + request (~.gcd_participant.AnalyzeContentRequest): + The request object. The request message for + [Participants.AnalyzeContent][google.cloud.dialogflow.v2beta1.Participants.AnalyzeContent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_participant.AnalyzeContentResponse: + The response message for + [Participants.AnalyzeContent][google.cloud.dialogflow.v2beta1.Participants.AnalyzeContent]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{participant=projects/*/conversations/*/participants/*}:analyzeContent", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{participant=projects/*/locations/*/conversations/*/participants/*}:analyzeContent", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_analyze_content(request, metadata) + pb_request = gcd_participant.AnalyzeContentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_participant.AnalyzeContentResponse() + pb_resp = gcd_participant.AnalyzeContentResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_analyze_content(resp) + return resp + + class _CompileSuggestion(ParticipantsRestStub): + def __hash__(self): + return hash("CompileSuggestion") + + def __call__( + self, + request: participant.CompileSuggestionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.CompileSuggestionResponse: + r"""Call the compile suggestion method over HTTP. + + Args: + request (~.participant.CompileSuggestionRequest): + The request object. The request message for + [Participants.CompileSuggestion][google.cloud.dialogflow.v2beta1.Participants.CompileSuggestion]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.CompileSuggestionResponse: + The response message for + [Participants.CompileSuggestion][google.cloud.dialogflow.v2beta1.Participants.CompileSuggestion]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/conversations/*/participants/*}/suggestions:compile", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_compile_suggestion( + request, metadata + ) + pb_request = participant.CompileSuggestionRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.CompileSuggestionResponse() + pb_resp = participant.CompileSuggestionResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_compile_suggestion(resp) + return resp + + class _CreateParticipant(ParticipantsRestStub): + def __hash__(self): + return hash("CreateParticipant") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_participant.CreateParticipantRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_participant.Participant: + r"""Call the create participant method over HTTP. + + Args: + request (~.gcd_participant.CreateParticipantRequest): + The request object. The request message for + [Participants.CreateParticipant][google.cloud.dialogflow.v2beta1.Participants.CreateParticipant]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_participant.Participant: + Represents a conversation participant + (human agent, virtual agent, end-user). + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/conversations/*}/participants", + "body": "participant", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/conversations/*}/participants", + "body": "participant", + }, + ] + request, metadata = self._interceptor.pre_create_participant( + request, metadata + ) + pb_request = gcd_participant.CreateParticipantRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_participant.Participant() + pb_resp = gcd_participant.Participant.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_participant(resp) + return resp + + class _GetParticipant(ParticipantsRestStub): + def __hash__(self): + return hash("GetParticipant") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: participant.GetParticipantRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.Participant: + r"""Call the get participant method over HTTP. + + Args: + request (~.participant.GetParticipantRequest): + The request object. The request message for + [Participants.GetParticipant][google.cloud.dialogflow.v2beta1.Participants.GetParticipant]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.Participant: + Represents a conversation participant + (human agent, virtual agent, end-user). + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/conversations/*/participants/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/conversations/*/participants/*}", + }, + ] + request, metadata = self._interceptor.pre_get_participant(request, metadata) + pb_request = participant.GetParticipantRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.Participant() + pb_resp = participant.Participant.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_participant(resp) + return resp + + class _ListParticipants(ParticipantsRestStub): + def __hash__(self): + return hash("ListParticipants") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: participant.ListParticipantsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.ListParticipantsResponse: + r"""Call the list participants method over HTTP. + + Args: + request (~.participant.ListParticipantsRequest): + The request object. The request message for + [Participants.ListParticipants][google.cloud.dialogflow.v2beta1.Participants.ListParticipants]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.ListParticipantsResponse: + The response message for + [Participants.ListParticipants][google.cloud.dialogflow.v2beta1.Participants.ListParticipants]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/conversations/*}/participants", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/conversations/*}/participants", + }, + ] + request, metadata = self._interceptor.pre_list_participants( + request, metadata + ) + pb_request = participant.ListParticipantsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.ListParticipantsResponse() + pb_resp = participant.ListParticipantsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_participants(resp) + return resp + + class _ListSuggestions(ParticipantsRestStub): + def __hash__(self): + return hash("ListSuggestions") + + def __call__( + self, + request: participant.ListSuggestionsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.ListSuggestionsResponse: + r"""Call the list suggestions method over HTTP. + + Args: + request (~.participant.ListSuggestionsRequest): + The request object. The request message for + [Participants.ListSuggestions][google.cloud.dialogflow.v2beta1.Participants.ListSuggestions]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.ListSuggestionsResponse: + The response message for + [Participants.ListSuggestions][google.cloud.dialogflow.v2beta1.Participants.ListSuggestions]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/conversations/*/participants/*}/suggestions", + }, + ] + request, metadata = self._interceptor.pre_list_suggestions( + request, metadata + ) + pb_request = participant.ListSuggestionsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.ListSuggestionsResponse() + pb_resp = participant.ListSuggestionsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_suggestions(resp) + return resp + + class _StreamingAnalyzeContent(ParticipantsRestStub): + def __hash__(self): + return hash("StreamingAnalyzeContent") + + def __call__( + self, + request: participant.StreamingAnalyzeContentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> rest_streaming.ResponseIterator: + raise NotImplementedError( + "Method StreamingAnalyzeContent is not available over REST transport" + ) + + class _SuggestArticles(ParticipantsRestStub): + def __hash__(self): + return hash("SuggestArticles") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: participant.SuggestArticlesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.SuggestArticlesResponse: + r"""Call the suggest articles method over HTTP. + + Args: + request (~.participant.SuggestArticlesRequest): + The request object. The request message for + [Participants.SuggestArticles][google.cloud.dialogflow.v2beta1.Participants.SuggestArticles]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.SuggestArticlesResponse: + The response message for + [Participants.SuggestArticles][google.cloud.dialogflow.v2beta1.Participants.SuggestArticles]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestArticles", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/conversations/*/participants/*}/suggestions:suggestArticles", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_suggest_articles( + request, metadata + ) + pb_request = participant.SuggestArticlesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.SuggestArticlesResponse() + pb_resp = participant.SuggestArticlesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_suggest_articles(resp) + return resp + + class _SuggestFaqAnswers(ParticipantsRestStub): + def __hash__(self): + return hash("SuggestFaqAnswers") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: participant.SuggestFaqAnswersRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.SuggestFaqAnswersResponse: + r"""Call the suggest faq answers method over HTTP. + + Args: + request (~.participant.SuggestFaqAnswersRequest): + The request object. The request message for + [Participants.SuggestFaqAnswers][google.cloud.dialogflow.v2beta1.Participants.SuggestFaqAnswers]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.SuggestFaqAnswersResponse: + The request message for + [Participants.SuggestFaqAnswers][google.cloud.dialogflow.v2beta1.Participants.SuggestFaqAnswers]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestFaqAnswers", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/conversations/*/participants/*}/suggestions:suggestFaqAnswers", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_suggest_faq_answers( + request, metadata + ) + pb_request = participant.SuggestFaqAnswersRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.SuggestFaqAnswersResponse() + pb_resp = participant.SuggestFaqAnswersResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_suggest_faq_answers(resp) + return resp + + class _SuggestSmartReplies(ParticipantsRestStub): + def __hash__(self): + return hash("SuggestSmartReplies") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: participant.SuggestSmartRepliesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> participant.SuggestSmartRepliesResponse: + r"""Call the suggest smart replies method over HTTP. + + Args: + request (~.participant.SuggestSmartRepliesRequest): + The request object. The request message for + [Participants.SuggestSmartReplies][google.cloud.dialogflow.v2beta1.Participants.SuggestSmartReplies]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.participant.SuggestSmartRepliesResponse: + The response message for + [Participants.SuggestSmartReplies][google.cloud.dialogflow.v2beta1.Participants.SuggestSmartReplies]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestSmartReplies", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/conversations/*/participants/*}/suggestions:suggestSmartReplies", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_suggest_smart_replies( + request, metadata + ) + pb_request = participant.SuggestSmartRepliesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = participant.SuggestSmartRepliesResponse() + pb_resp = participant.SuggestSmartRepliesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_suggest_smart_replies(resp) + return resp + + class _UpdateParticipant(ParticipantsRestStub): + def __hash__(self): + return hash("UpdateParticipant") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_participant.UpdateParticipantRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_participant.Participant: + r"""Call the update participant method over HTTP. + + Args: + request (~.gcd_participant.UpdateParticipantRequest): + The request object. The request message for + [Participants.UpdateParticipant][google.cloud.dialogflow.v2beta1.Participants.UpdateParticipant]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_participant.Participant: + Represents a conversation participant + (human agent, virtual agent, end-user). + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{participant.name=projects/*/conversations/*/participants/*}", + "body": "participant", + }, + { + "method": "patch", + "uri": "/v2beta1/{participant.name=projects/*/locations/*/conversations/*/participants/*}", + "body": "participant", + }, + ] + request, metadata = self._interceptor.pre_update_participant( + request, metadata + ) + pb_request = gcd_participant.UpdateParticipantRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_participant.Participant() + pb_resp = gcd_participant.Participant.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_participant(resp) + return resp + + @property + def analyze_content( + self, + ) -> Callable[ + [gcd_participant.AnalyzeContentRequest], gcd_participant.AnalyzeContentResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._AnalyzeContent(self._session, self._host, self._interceptor) # type: ignore + + @property + def compile_suggestion( + self, + ) -> Callable[ + [participant.CompileSuggestionRequest], participant.CompileSuggestionResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CompileSuggestion(self._session, self._host, self._interceptor) # type: ignore + + @property + def create_participant( + self, + ) -> Callable[ + [gcd_participant.CreateParticipantRequest], gcd_participant.Participant + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateParticipant(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_participant( + self, + ) -> Callable[[participant.GetParticipantRequest], participant.Participant]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetParticipant(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_participants( + self, + ) -> Callable[ + [participant.ListParticipantsRequest], participant.ListParticipantsResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListParticipants(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_suggestions( + self, + ) -> Callable[ + [participant.ListSuggestionsRequest], participant.ListSuggestionsResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListSuggestions(self._session, self._host, self._interceptor) # type: ignore + + @property + def streaming_analyze_content( + self, + ) -> Callable[ + [participant.StreamingAnalyzeContentRequest], + participant.StreamingAnalyzeContentResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._StreamingAnalyzeContent(self._session, self._host, self._interceptor) # type: ignore + + @property + def suggest_articles( + self, + ) -> Callable[ + [participant.SuggestArticlesRequest], participant.SuggestArticlesResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SuggestArticles(self._session, self._host, self._interceptor) # type: ignore + + @property + def suggest_faq_answers( + self, + ) -> Callable[ + [participant.SuggestFaqAnswersRequest], participant.SuggestFaqAnswersResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SuggestFaqAnswers(self._session, self._host, self._interceptor) # type: ignore + + @property + def suggest_smart_replies( + self, + ) -> Callable[ + [participant.SuggestSmartRepliesRequest], + participant.SuggestSmartRepliesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._SuggestSmartReplies(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_participant( + self, + ) -> Callable[ + [gcd_participant.UpdateParticipantRequest], gcd_participant.Participant + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateParticipant(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(ParticipantsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(ParticipantsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(ParticipantsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(ParticipantsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(ParticipantsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("ParticipantsRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/session_entity_types/client.py b/google/cloud/dialogflow_v2beta1/services/session_entity_types/client.py index bb55d2739..2319f279d 100644 --- a/google/cloud/dialogflow_v2beta1/services/session_entity_types/client.py +++ b/google/cloud/dialogflow_v2beta1/services/session_entity_types/client.py @@ -60,6 +60,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, SessionEntityTypesTransport from .transports.grpc import SessionEntityTypesGrpcTransport from .transports.grpc_asyncio import SessionEntityTypesGrpcAsyncIOTransport +from .transports.rest import SessionEntityTypesRestTransport class SessionEntityTypesClientMeta(type): @@ -75,6 +76,7 @@ class SessionEntityTypesClientMeta(type): ) # type: Dict[str, Type[SessionEntityTypesTransport]] _transport_registry["grpc"] = SessionEntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = SessionEntityTypesGrpcAsyncIOTransport + _transport_registry["rest"] = SessionEntityTypesRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/session_entity_types/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/session_entity_types/transports/__init__.py index d21afca4f..9dfccaa53 100644 --- a/google/cloud/dialogflow_v2beta1/services/session_entity_types/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/session_entity_types/transports/__init__.py @@ -19,6 +19,7 @@ from .base import SessionEntityTypesTransport from .grpc import SessionEntityTypesGrpcTransport from .grpc_asyncio import SessionEntityTypesGrpcAsyncIOTransport +from .rest import SessionEntityTypesRestInterceptor, SessionEntityTypesRestTransport # Compile a registry of transports. _transport_registry = ( @@ -26,9 +27,12 @@ ) # type: Dict[str, Type[SessionEntityTypesTransport]] _transport_registry["grpc"] = SessionEntityTypesGrpcTransport _transport_registry["grpc_asyncio"] = SessionEntityTypesGrpcAsyncIOTransport +_transport_registry["rest"] = SessionEntityTypesRestTransport __all__ = ( "SessionEntityTypesTransport", "SessionEntityTypesGrpcTransport", "SessionEntityTypesGrpcAsyncIOTransport", + "SessionEntityTypesRestTransport", + "SessionEntityTypesRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/session_entity_types/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/session_entity_types/transports/rest.py new file mode 100644 index 000000000..47e4d5d15 --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/session_entity_types/transports/rest.py @@ -0,0 +1,1408 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2beta1.types import ( + session_entity_type as gcd_session_entity_type, +) +from google.cloud.dialogflow_v2beta1.types import session_entity_type + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import SessionEntityTypesTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class SessionEntityTypesRestInterceptor: + """Interceptor for SessionEntityTypes. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the SessionEntityTypesRestTransport. + + .. code-block:: python + class MyCustomSessionEntityTypesInterceptor(SessionEntityTypesRestInterceptor): + def pre_create_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_session_entity_types(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_session_entity_types(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_session_entity_type(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_session_entity_type(self, response): + logging.log(f"Received response: {response}") + return response + + transport = SessionEntityTypesRestTransport(interceptor=MyCustomSessionEntityTypesInterceptor()) + client = SessionEntityTypesClient(transport=transport) + + + """ + + def pre_create_session_entity_type( + self, + request: gcd_session_entity_type.CreateSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_session_entity_type.CreateSessionEntityTypeRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for create_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_create_session_entity_type( + self, response: gcd_session_entity_type.SessionEntityType + ) -> gcd_session_entity_type.SessionEntityType: + """Post-rpc interceptor for create_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_delete_session_entity_type( + self, + request: session_entity_type.DeleteSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.DeleteSessionEntityTypeRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for delete_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def pre_get_session_entity_type( + self, + request: session_entity_type.GetSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.GetSessionEntityTypeRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for get_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_session_entity_type( + self, response: session_entity_type.SessionEntityType + ) -> session_entity_type.SessionEntityType: + """Post-rpc interceptor for get_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_session_entity_types( + self, + request: session_entity_type.ListSessionEntityTypesRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + session_entity_type.ListSessionEntityTypesRequest, Sequence[Tuple[str, str]] + ]: + """Pre-rpc interceptor for list_session_entity_types + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_session_entity_types( + self, response: session_entity_type.ListSessionEntityTypesResponse + ) -> session_entity_type.ListSessionEntityTypesResponse: + """Post-rpc interceptor for list_session_entity_types + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_update_session_entity_type( + self, + request: gcd_session_entity_type.UpdateSessionEntityTypeRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[ + gcd_session_entity_type.UpdateSessionEntityTypeRequest, + Sequence[Tuple[str, str]], + ]: + """Pre-rpc interceptor for update_session_entity_type + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_update_session_entity_type( + self, response: gcd_session_entity_type.SessionEntityType + ) -> gcd_session_entity_type.SessionEntityType: + """Post-rpc interceptor for update_session_entity_type + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the SessionEntityTypes server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the SessionEntityTypes server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class SessionEntityTypesRestStub: + _session: AuthorizedSession + _host: str + _interceptor: SessionEntityTypesRestInterceptor + + +class SessionEntityTypesRestTransport(SessionEntityTypesTransport): + """REST backend transport for SessionEntityTypes. + + Service for managing + [SessionEntityTypes][google.cloud.dialogflow.v2beta1.SessionEntityType]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[SessionEntityTypesRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or SessionEntityTypesRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("CreateSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_session_entity_type.CreateSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_session_entity_type.SessionEntityType: + r"""Call the create session entity + type method over HTTP. + + Args: + request (~.gcd_session_entity_type.CreateSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.CreateSessionEntityType][google.cloud.dialogflow.v2beta1.SessionEntityTypes.CreateSessionEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_session_entity_type.SessionEntityType: + A session represents a conversation between a Dialogflow + agent and an end-user. You can create special entities, + called session entities, during a session. Session + entities can extend or replace custom entity types and + only exist during the session that they were created + for. All session data, including session entities, is + stored by Dialogflow for 20 minutes. + + For more information, see the `session entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent/environments/*/users/*/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/environments/*/users/*/sessions/*}/entityTypes", + "body": "session_entity_type", + }, + ] + request, metadata = self._interceptor.pre_create_session_entity_type( + request, metadata + ) + pb_request = gcd_session_entity_type.CreateSessionEntityTypeRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_session_entity_type.SessionEntityType() + pb_resp = gcd_session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_session_entity_type(resp) + return resp + + class _DeleteSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("DeleteSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: session_entity_type.DeleteSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete session entity + type method over HTTP. + + Args: + request (~.session_entity_type.DeleteSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.DeleteSessionEntityType][google.cloud.dialogflow.v2beta1.SessionEntityTypes.DeleteSessionEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/agent/sessions/*/entityTypes/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/sessions/*/entityTypes/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_session_entity_type( + request, metadata + ) + pb_request = session_entity_type.DeleteSessionEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("GetSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: session_entity_type.GetSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session_entity_type.SessionEntityType: + r"""Call the get session entity type method over HTTP. + + Args: + request (~.session_entity_type.GetSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.GetSessionEntityType][google.cloud.dialogflow.v2beta1.SessionEntityTypes.GetSessionEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.session_entity_type.SessionEntityType: + A session represents a conversation between a Dialogflow + agent and an end-user. You can create special entities, + called session entities, during a session. Session + entities can extend or replace custom entity types and + only exist during the session that they were created + for. All session data, including session entities, is + stored by Dialogflow for 20 minutes. + + For more information, see the `session entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/agent/sessions/*/entityTypes/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/sessions/*/entityTypes/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + }, + ] + request, metadata = self._interceptor.pre_get_session_entity_type( + request, metadata + ) + pb_request = session_entity_type.GetSessionEntityTypeRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = session_entity_type.SessionEntityType() + pb_resp = session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_session_entity_type(resp) + return resp + + class _ListSessionEntityTypes(SessionEntityTypesRestStub): + def __hash__(self): + return hash("ListSessionEntityTypes") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: session_entity_type.ListSessionEntityTypesRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> session_entity_type.ListSessionEntityTypesResponse: + r"""Call the list session entity types method over HTTP. + + Args: + request (~.session_entity_type.ListSessionEntityTypesRequest): + The request object. The request message for + [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.v2beta1.SessionEntityTypes.ListSessionEntityTypes]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.session_entity_type.ListSessionEntityTypesResponse: + The response message for + [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.v2beta1.SessionEntityTypes.ListSessionEntityTypes]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent/sessions/*}/entityTypes", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent/environments/*/users/*/sessions/*}/entityTypes", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/sessions/*}/entityTypes", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent/environments/*/users/*/sessions/*}/entityTypes", + }, + ] + request, metadata = self._interceptor.pre_list_session_entity_types( + request, metadata + ) + pb_request = session_entity_type.ListSessionEntityTypesRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = session_entity_type.ListSessionEntityTypesResponse() + pb_resp = session_entity_type.ListSessionEntityTypesResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_session_entity_types(resp) + return resp + + class _UpdateSessionEntityType(SessionEntityTypesRestStub): + def __hash__(self): + return hash("UpdateSessionEntityType") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_session_entity_type.UpdateSessionEntityTypeRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_session_entity_type.SessionEntityType: + r"""Call the update session entity + type method over HTTP. + + Args: + request (~.gcd_session_entity_type.UpdateSessionEntityTypeRequest): + The request object. The request message for + [SessionEntityTypes.UpdateSessionEntityType][google.cloud.dialogflow.v2beta1.SessionEntityTypes.UpdateSessionEntityType]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_session_entity_type.SessionEntityType: + A session represents a conversation between a Dialogflow + agent and an end-user. You can create special entities, + called session entities, during a session. Session + entities can extend or replace custom entity types and + only exist during the session that they were created + for. All session data, including session entities, is + stored by Dialogflow for 20 minutes. + + For more information, see the `session entity + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{session_entity_type.name=projects/*/agent/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + { + "method": "patch", + "uri": "/v2beta1/{session_entity_type.name=projects/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + { + "method": "patch", + "uri": "/v2beta1/{session_entity_type.name=projects/*/locations/*/agent/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + { + "method": "patch", + "uri": "/v2beta1/{session_entity_type.name=projects/*/locations/*/agent/environments/*/users/*/sessions/*/entityTypes/*}", + "body": "session_entity_type", + }, + ] + request, metadata = self._interceptor.pre_update_session_entity_type( + request, metadata + ) + pb_request = gcd_session_entity_type.UpdateSessionEntityTypeRequest.pb( + request + ) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_session_entity_type.SessionEntityType() + pb_resp = gcd_session_entity_type.SessionEntityType.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_session_entity_type(resp) + return resp + + @property + def create_session_entity_type( + self, + ) -> Callable[ + [gcd_session_entity_type.CreateSessionEntityTypeRequest], + gcd_session_entity_type.SessionEntityType, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_session_entity_type( + self, + ) -> Callable[ + [session_entity_type.DeleteSessionEntityTypeRequest], empty_pb2.Empty + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_session_entity_type( + self, + ) -> Callable[ + [session_entity_type.GetSessionEntityTypeRequest], + session_entity_type.SessionEntityType, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_session_entity_types( + self, + ) -> Callable[ + [session_entity_type.ListSessionEntityTypesRequest], + session_entity_type.ListSessionEntityTypesResponse, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListSessionEntityTypes(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_session_entity_type( + self, + ) -> Callable[ + [gcd_session_entity_type.UpdateSessionEntityTypeRequest], + gcd_session_entity_type.SessionEntityType, + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateSessionEntityType(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(SessionEntityTypesRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(SessionEntityTypesRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(SessionEntityTypesRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(SessionEntityTypesRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(SessionEntityTypesRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("SessionEntityTypesRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/sessions/client.py b/google/cloud/dialogflow_v2beta1/services/sessions/client.py index 705ec8e89..1395bc915 100644 --- a/google/cloud/dialogflow_v2beta1/services/sessions/client.py +++ b/google/cloud/dialogflow_v2beta1/services/sessions/client.py @@ -59,6 +59,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, SessionsTransport from .transports.grpc import SessionsGrpcTransport from .transports.grpc_asyncio import SessionsGrpcAsyncIOTransport +from .transports.rest import SessionsRestTransport class SessionsClientMeta(type): @@ -72,6 +73,7 @@ class SessionsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[SessionsTransport]] _transport_registry["grpc"] = SessionsGrpcTransport _transport_registry["grpc_asyncio"] = SessionsGrpcAsyncIOTransport + _transport_registry["rest"] = SessionsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/sessions/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/sessions/transports/__init__.py index 72ba9b72a..27547f74a 100644 --- a/google/cloud/dialogflow_v2beta1/services/sessions/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/sessions/transports/__init__.py @@ -19,14 +19,18 @@ from .base import SessionsTransport from .grpc import SessionsGrpcTransport from .grpc_asyncio import SessionsGrpcAsyncIOTransport +from .rest import SessionsRestInterceptor, SessionsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[SessionsTransport]] _transport_registry["grpc"] = SessionsGrpcTransport _transport_registry["grpc_asyncio"] = SessionsGrpcAsyncIOTransport +_transport_registry["rest"] = SessionsRestTransport __all__ = ( "SessionsTransport", "SessionsGrpcTransport", "SessionsGrpcAsyncIOTransport", + "SessionsRestTransport", + "SessionsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/sessions/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/sessions/transports/rest.py new file mode 100644 index 000000000..96b587a34 --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/sessions/transports/rest.py @@ -0,0 +1,816 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.cloud.dialogflow_v2beta1.types import session +from google.cloud.dialogflow_v2beta1.types import session as gcd_session + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import SessionsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class SessionsRestInterceptor: + """Interceptor for Sessions. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the SessionsRestTransport. + + .. code-block:: python + class MyCustomSessionsInterceptor(SessionsRestInterceptor): + def pre_detect_intent(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_detect_intent(self, response): + logging.log(f"Received response: {response}") + return response + + transport = SessionsRestTransport(interceptor=MyCustomSessionsInterceptor()) + client = SessionsClient(transport=transport) + + + """ + + def pre_detect_intent( + self, + request: gcd_session.DetectIntentRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_session.DetectIntentRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for detect_intent + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_detect_intent( + self, response: gcd_session.DetectIntentResponse + ) -> gcd_session.DetectIntentResponse: + """Post-rpc interceptor for detect_intent + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Sessions server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Sessions server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class SessionsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: SessionsRestInterceptor + + +class SessionsRestTransport(SessionsTransport): + """REST backend transport for Sessions. + + A service used for session interactions. + + For more information, see the `API interactions + guide `__. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[SessionsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or SessionsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _DetectIntent(SessionsRestStub): + def __hash__(self): + return hash("DetectIntent") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_session.DetectIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_session.DetectIntentResponse: + r"""Call the detect intent method over HTTP. + + Args: + request (~.gcd_session.DetectIntentRequest): + The request object. The request to detect user's intent. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_session.DetectIntentResponse: + The message returned from the + DetectIntent method. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{session=projects/*/agent/sessions/*}:detectIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{session=projects/*/agent/environments/*/users/*/sessions/*}:detectIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{session=projects/*/locations/*/agent/sessions/*}:detectIntent", + "body": "*", + }, + { + "method": "post", + "uri": "/v2beta1/{session=projects/*/locations/*/agent/environments/*/users/*/sessions/*}:detectIntent", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_detect_intent(request, metadata) + pb_request = gcd_session.DetectIntentRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_session.DetectIntentResponse() + pb_resp = gcd_session.DetectIntentResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_detect_intent(resp) + return resp + + class _StreamingDetectIntent(SessionsRestStub): + def __hash__(self): + return hash("StreamingDetectIntent") + + def __call__( + self, + request: session.StreamingDetectIntentRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> rest_streaming.ResponseIterator: + raise NotImplementedError( + "Method StreamingDetectIntent is not available over REST transport" + ) + + @property + def detect_intent( + self, + ) -> Callable[[gcd_session.DetectIntentRequest], gcd_session.DetectIntentResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DetectIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def streaming_detect_intent( + self, + ) -> Callable[ + [session.StreamingDetectIntentRequest], session.StreamingDetectIntentResponse + ]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._StreamingDetectIntent(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(SessionsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(SessionsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(SessionsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(SessionsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(SessionsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("SessionsRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/services/versions/client.py b/google/cloud/dialogflow_v2beta1/services/versions/client.py index c3e26a0a1..f18fe9392 100644 --- a/google/cloud/dialogflow_v2beta1/services/versions/client.py +++ b/google/cloud/dialogflow_v2beta1/services/versions/client.py @@ -58,6 +58,7 @@ from .transports.base import DEFAULT_CLIENT_INFO, VersionsTransport from .transports.grpc import VersionsGrpcTransport from .transports.grpc_asyncio import VersionsGrpcAsyncIOTransport +from .transports.rest import VersionsRestTransport class VersionsClientMeta(type): @@ -71,6 +72,7 @@ class VersionsClientMeta(type): _transport_registry = OrderedDict() # type: Dict[str, Type[VersionsTransport]] _transport_registry["grpc"] = VersionsGrpcTransport _transport_registry["grpc_asyncio"] = VersionsGrpcAsyncIOTransport + _transport_registry["rest"] = VersionsRestTransport def get_transport_class( cls, diff --git a/google/cloud/dialogflow_v2beta1/services/versions/transports/__init__.py b/google/cloud/dialogflow_v2beta1/services/versions/transports/__init__.py index e31c2163a..e921ca1d4 100644 --- a/google/cloud/dialogflow_v2beta1/services/versions/transports/__init__.py +++ b/google/cloud/dialogflow_v2beta1/services/versions/transports/__init__.py @@ -19,14 +19,18 @@ from .base import VersionsTransport from .grpc import VersionsGrpcTransport from .grpc_asyncio import VersionsGrpcAsyncIOTransport +from .rest import VersionsRestInterceptor, VersionsRestTransport # Compile a registry of transports. _transport_registry = OrderedDict() # type: Dict[str, Type[VersionsTransport]] _transport_registry["grpc"] = VersionsGrpcTransport _transport_registry["grpc_asyncio"] = VersionsGrpcAsyncIOTransport +_transport_registry["rest"] = VersionsRestTransport __all__ = ( "VersionsTransport", "VersionsGrpcTransport", "VersionsGrpcAsyncIOTransport", + "VersionsRestTransport", + "VersionsRestInterceptor", ) diff --git a/google/cloud/dialogflow_v2beta1/services/versions/transports/rest.py b/google/cloud/dialogflow_v2beta1/services/versions/transports/rest.py new file mode 100644 index 000000000..3d1b0509d --- /dev/null +++ b/google/cloud/dialogflow_v2beta1/services/versions/transports/rest.py @@ -0,0 +1,1334 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import dataclasses +import json # type: ignore +import re +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, path_template, rest_helpers, rest_streaming +from google.api_core import exceptions as core_exceptions +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.transport.requests import AuthorizedSession # type: ignore +from google.cloud.location import locations_pb2 # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import json_format +import grpc # type: ignore +from requests import __version__ as requests_version + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + + +from google.protobuf import empty_pb2 # type: ignore + +from google.cloud.dialogflow_v2beta1.types import version +from google.cloud.dialogflow_v2beta1.types import version as gcd_version + +from .base import DEFAULT_CLIENT_INFO as BASE_DEFAULT_CLIENT_INFO +from .base import VersionsTransport + +DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, + grpc_version=None, + rest_version=requests_version, +) + + +class VersionsRestInterceptor: + """Interceptor for Versions. + + Interceptors are used to manipulate requests, request metadata, and responses + in arbitrary ways. + Example use cases include: + * Logging + * Verifying requests according to service or custom semantics + * Stripping extraneous information from responses + + These use cases and more can be enabled by injecting an + instance of a custom subclass when constructing the VersionsRestTransport. + + .. code-block:: python + class MyCustomVersionsInterceptor(VersionsRestInterceptor): + def pre_create_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_create_version(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_delete_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def pre_get_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_get_version(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_list_versions(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_list_versions(self, response): + logging.log(f"Received response: {response}") + return response + + def pre_update_version(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_update_version(self, response): + logging.log(f"Received response: {response}") + return response + + transport = VersionsRestTransport(interceptor=MyCustomVersionsInterceptor()) + client = VersionsClient(transport=transport) + + + """ + + def pre_create_version( + self, + request: gcd_version.CreateVersionRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_version.CreateVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for create_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_create_version(self, response: gcd_version.Version) -> gcd_version.Version: + """Post-rpc interceptor for create_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_delete_version( + self, request: version.DeleteVersionRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.DeleteVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for delete_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def pre_get_version( + self, request: version.GetVersionRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.GetVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_version(self, response: version.Version) -> version.Version: + """Post-rpc interceptor for get_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_versions( + self, request: version.ListVersionsRequest, metadata: Sequence[Tuple[str, str]] + ) -> Tuple[version.ListVersionsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_versions + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_versions( + self, response: version.ListVersionsResponse + ) -> version.ListVersionsResponse: + """Post-rpc interceptor for list_versions + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_update_version( + self, + request: gcd_version.UpdateVersionRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[gcd_version.UpdateVersionRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for update_version + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_update_version(self, response: gcd_version.Version) -> gcd_version.Version: + """Post-rpc interceptor for update_version + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_get_location( + self, + request: locations_pb2.GetLocationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.GetLocationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_location + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_location( + self, response: locations_pb2.Location + ) -> locations_pb2.Location: + """Post-rpc interceptor for get_location + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_locations( + self, + request: locations_pb2.ListLocationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[locations_pb2.ListLocationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_locations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_locations( + self, response: locations_pb2.ListLocationsResponse + ) -> locations_pb2.ListLocationsResponse: + """Post-rpc interceptor for list_locations + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_cancel_operation( + self, + request: operations_pb2.CancelOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.CancelOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_cancel_operation(self, response: None) -> None: + """Post-rpc interceptor for cancel_operation + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_get_operation( + self, + request: operations_pb2.GetOperationRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.GetOperationRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for get_operation + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_get_operation( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for get_operation + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + def pre_list_operations( + self, + request: operations_pb2.ListOperationsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[operations_pb2.ListOperationsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for list_operations + + Override in a subclass to manipulate the request or metadata + before they are sent to the Versions server. + """ + return request, metadata + + def post_list_operations( + self, response: operations_pb2.ListOperationsResponse + ) -> operations_pb2.ListOperationsResponse: + """Post-rpc interceptor for list_operations + + Override in a subclass to manipulate the response + after it is returned by the Versions server but before + it is returned to user code. + """ + return response + + +@dataclasses.dataclass +class VersionsRestStub: + _session: AuthorizedSession + _host: str + _interceptor: VersionsRestInterceptor + + +class VersionsRestTransport(VersionsTransport): + """REST backend transport for Versions. + + Service for managing + [Versions][google.cloud.dialogflow.v2beta1.Version]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends JSON representations of protocol buffers over HTTP/1.1 + + """ + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: Optional[ga_credentials.Credentials] = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + url_scheme: str = "https", + interceptor: Optional[VersionsRestInterceptor] = None, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + client_cert_source_for_mtls (Callable[[], Tuple[bytes, bytes]]): Client + certificate to configure mutual TLS HTTP channel. It is ignored + if ``channel`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you are developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + url_scheme: the protocol scheme for the API endpoint. Normally + "https", but for testing or local servers, + "http" can be specified. + """ + # Run the base constructor + # TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc. + # TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the + # credentials object + maybe_url_match = re.match("^(?Phttp(?:s)?://)?(?P.*)$", host) + if maybe_url_match is None: + raise ValueError( + f"Unexpected hostname structure: {host}" + ) # pragma: NO COVER + + url_match_items = maybe_url_match.groupdict() + + host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host + + super().__init__( + host=host, + credentials=credentials, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + self._session = AuthorizedSession( + self._credentials, default_host=self.DEFAULT_HOST + ) + if client_cert_source_for_mtls: + self._session.configure_mtls_channel(client_cert_source_for_mtls) + self._interceptor = interceptor or VersionsRestInterceptor() + self._prep_wrapped_messages(client_info) + + class _CreateVersion(VersionsRestStub): + def __hash__(self): + return hash("CreateVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_version.CreateVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_version.Version: + r"""Call the create version method over HTTP. + + Args: + request (~.gcd_version.CreateVersionRequest): + The request object. The request message for + [Versions.CreateVersion][google.cloud.dialogflow.v2beta1.Versions.CreateVersion]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_version.Version: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/agent}/versions", + "body": "version", + }, + { + "method": "post", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/versions", + "body": "version", + }, + ] + request, metadata = self._interceptor.pre_create_version(request, metadata) + pb_request = gcd_version.CreateVersionRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_version.Version() + pb_resp = gcd_version.Version.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_version(resp) + return resp + + class _DeleteVersion(VersionsRestStub): + def __hash__(self): + return hash("DeleteVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: version.DeleteVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ): + r"""Call the delete version method over HTTP. + + Args: + request (~.version.DeleteVersionRequest): + The request object. The request message for + [Versions.DeleteVersion][google.cloud.dialogflow.v2beta1.Versions.DeleteVersion]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/agent/versions/*}", + }, + { + "method": "delete", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/versions/*}", + }, + ] + request, metadata = self._interceptor.pre_delete_version(request, metadata) + pb_request = version.DeleteVersionRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + class _GetVersion(VersionsRestStub): + def __hash__(self): + return hash("GetVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: version.GetVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> version.Version: + r"""Call the get version method over HTTP. + + Args: + request (~.version.GetVersionRequest): + The request object. The request message for + [Versions.GetVersion][google.cloud.dialogflow.v2beta1.Versions.GetVersion]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.version.Version: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/agent/versions/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/agent/versions/*}", + }, + ] + request, metadata = self._interceptor.pre_get_version(request, metadata) + pb_request = version.GetVersionRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = version.Version() + pb_resp = version.Version.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_version(resp) + return resp + + class _ListVersions(VersionsRestStub): + def __hash__(self): + return hash("ListVersions") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: version.ListVersionsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> version.ListVersionsResponse: + r"""Call the list versions method over HTTP. + + Args: + request (~.version.ListVersionsRequest): + The request object. The request message for + [Versions.ListVersions][google.cloud.dialogflow.v2beta1.Versions.ListVersions]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.version.ListVersionsResponse: + The response message for + [Versions.ListVersions][google.cloud.dialogflow.v2beta1.Versions.ListVersions]. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/agent}/versions", + }, + { + "method": "get", + "uri": "/v2beta1/{parent=projects/*/locations/*/agent}/versions", + }, + ] + request, metadata = self._interceptor.pre_list_versions(request, metadata) + pb_request = version.ListVersionsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = version.ListVersionsResponse() + pb_resp = version.ListVersionsResponse.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_versions(resp) + return resp + + class _UpdateVersion(VersionsRestStub): + def __hash__(self): + return hash("UpdateVersion") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = { + "updateMask": {}, + } + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + def __call__( + self, + request: gcd_version.UpdateVersionRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcd_version.Version: + r"""Call the update version method over HTTP. + + Args: + request (~.gcd_version.UpdateVersionRequest): + The request object. The request message for + [Versions.UpdateVersion][google.cloud.dialogflow.v2beta1.Versions.UpdateVersion]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.gcd_version.Version: + You can create multiple versions of your agent and + publish them to separate environments. + + When you edit an agent, you are editing the draft agent. + At any point, you can save the draft agent as an agent + version, which is an immutable snapshot of your agent. + + When you save the draft agent, it is published to the + default environment. When you create agent versions, you + can publish them to custom environments. You can create + a variety of custom environments for: + + - testing + - development + - production + - etc. + + For more information, see the `versions and environments + guide `__. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "patch", + "uri": "/v2beta1/{version.name=projects/*/agent/versions/*}", + "body": "version", + }, + { + "method": "patch", + "uri": "/v2beta1/{version.name=projects/*/locations/*/agent/versions/*}", + "body": "version", + }, + ] + request, metadata = self._interceptor.pre_update_version(request, metadata) + pb_request = gcd_version.UpdateVersionRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + including_default_value_fields=False, + use_integers_for_enums=True, + ) + ) + query_params.update(self._get_unset_required_fields(query_params)) + + query_params["$alt"] = "json;enum-encoding=int" + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = gcd_version.Version() + pb_resp = gcd_version.Version.pb(resp) + + json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_version(resp) + return resp + + @property + def create_version( + self, + ) -> Callable[[gcd_version.CreateVersionRequest], gcd_version.Version]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._CreateVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def delete_version( + self, + ) -> Callable[[version.DeleteVersionRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_version(self) -> Callable[[version.GetVersionRequest], version.Version]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._GetVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def list_versions( + self, + ) -> Callable[[version.ListVersionsRequest], version.ListVersionsResponse]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._ListVersions(self._session, self._host, self._interceptor) # type: ignore + + @property + def update_version( + self, + ) -> Callable[[gcd_version.UpdateVersionRequest], gcd_version.Version]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._UpdateVersion(self._session, self._host, self._interceptor) # type: ignore + + @property + def get_location(self): + return self._GetLocation(self._session, self._host, self._interceptor) # type: ignore + + class _GetLocation(VersionsRestStub): + def __call__( + self, + request: locations_pb2.GetLocationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.Location: + + r"""Call the get location method over HTTP. + + Args: + request (locations_pb2.GetLocationRequest): + The request object for GetLocation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.Location: Response from GetLocation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_location(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.Location() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_location(resp) + return resp + + @property + def list_locations(self): + return self._ListLocations(self._session, self._host, self._interceptor) # type: ignore + + class _ListLocations(VersionsRestStub): + def __call__( + self, + request: locations_pb2.ListLocationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> locations_pb2.ListLocationsResponse: + + r"""Call the list locations method over HTTP. + + Args: + request (locations_pb2.ListLocationsRequest): + The request object for ListLocations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + locations_pb2.ListLocationsResponse: Response from ListLocations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/locations", + }, + ] + + request, metadata = self._interceptor.pre_list_locations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = locations_pb2.ListLocationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_locations(resp) + return resp + + @property + def cancel_operation(self): + return self._CancelOperation(self._session, self._host, self._interceptor) # type: ignore + + class _CancelOperation(VersionsRestStub): + def __call__( + self, + request: operations_pb2.CancelOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + + r"""Call the cancel operation method over HTTP. + + Args: + request (operations_pb2.CancelOperationRequest): + The request object for CancelOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/operations/*}:cancel", + }, + { + "method": "post", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}:cancel", + }, + ] + + request, metadata = self._interceptor.pre_cancel_operation( + request, metadata + ) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + return self._interceptor.post_cancel_operation(None) + + @property + def get_operation(self): + return self._GetOperation(self._session, self._host, self._interceptor) # type: ignore + + class _GetOperation(VersionsRestStub): + def __call__( + self, + request: operations_pb2.GetOperationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + + r"""Call the get operation method over HTTP. + + Args: + request (operations_pb2.GetOperationRequest): + The request object for GetOperation method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.Operation: Response from GetOperation method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/operations/*}", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*/operations/*}", + }, + ] + + request, metadata = self._interceptor.pre_get_operation(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.Operation() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_get_operation(resp) + return resp + + @property + def list_operations(self): + return self._ListOperations(self._session, self._host, self._interceptor) # type: ignore + + class _ListOperations(VersionsRestStub): + def __call__( + self, + request: operations_pb2.ListOperationsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + + r"""Call the list operations method over HTTP. + + Args: + request (operations_pb2.ListOperationsRequest): + The request object for ListOperations method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + operations_pb2.ListOperationsResponse: Response from ListOperations method. + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "get", + "uri": "/v2beta1/{name=projects/*}/operations", + }, + { + "method": "get", + "uri": "/v2beta1/{name=projects/*/locations/*}/operations", + }, + ] + + request, metadata = self._interceptor.pre_list_operations(request, metadata) + request_kwargs = json_format.MessageToDict(request) + transcoded_request = path_template.transcode(http_options, **request_kwargs) + + uri = transcoded_request["uri"] + method = transcoded_request["method"] + + # Jsonify the query params + query_params = json.loads(json.dumps(transcoded_request["query_params"])) + + # Send the request + headers = dict(metadata) + headers["Content-Type"] = "application/json" + + response = getattr(self._session, method)( + "{host}{uri}".format(host=self._host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params), + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + resp = operations_pb2.ListOperationsResponse() + resp = json_format.Parse(response.content.decode("utf-8"), resp) + resp = self._interceptor.post_list_operations(resp) + return resp + + @property + def kind(self) -> str: + return "rest" + + def close(self): + self._session.close() + + +__all__ = ("VersionsRestTransport",) diff --git a/google/cloud/dialogflow_v2beta1/types/agent.py b/google/cloud/dialogflow_v2beta1/types/agent.py index f8ea586b8..cc8d787da 100644 --- a/google/cloud/dialogflow_v2beta1/types/agent.py +++ b/google/cloud/dialogflow_v2beta1/types/agent.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/answer_record.py b/google/cloud/dialogflow_v2beta1/types/answer_record.py index 7c2e93e37..bf877b683 100644 --- a/google/cloud/dialogflow_v2beta1/types/answer_record.py +++ b/google/cloud/dialogflow_v2beta1/types/answer_record.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/audio_config.py b/google/cloud/dialogflow_v2beta1/types/audio_config.py index 13167694e..3e9f2565e 100644 --- a/google/cloud/dialogflow_v2beta1/types/audio_config.py +++ b/google/cloud/dialogflow_v2beta1/types/audio_config.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import duration_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/context.py b/google/cloud/dialogflow_v2beta1/types/context.py index e053d2349..5b189b63e 100644 --- a/google/cloud/dialogflow_v2beta1/types/context.py +++ b/google/cloud/dialogflow_v2beta1/types/context.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/conversation.py b/google/cloud/dialogflow_v2beta1/types/conversation.py index 7d5436026..80e7c8b08 100644 --- a/google/cloud/dialogflow_v2beta1/types/conversation.py +++ b/google/cloud/dialogflow_v2beta1/types/conversation.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import timestamp_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/conversation_event.py b/google/cloud/dialogflow_v2beta1/types/conversation_event.py index 31a658ceb..1994dd424 100644 --- a/google/cloud/dialogflow_v2beta1/types/conversation_event.py +++ b/google/cloud/dialogflow_v2beta1/types/conversation_event.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.rpc import status_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/conversation_profile.py b/google/cloud/dialogflow_v2beta1/types/conversation_profile.py index abe41d346..3c524b1e7 100644 --- a/google/cloud/dialogflow_v2beta1/types/conversation_profile.py +++ b/google/cloud/dialogflow_v2beta1/types/conversation_profile.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/document.py b/google/cloud/dialogflow_v2beta1/types/document.py index 41112e1e5..410d8b90e 100644 --- a/google/cloud/dialogflow_v2beta1/types/document.py +++ b/google/cloud/dialogflow_v2beta1/types/document.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/entity_type.py b/google/cloud/dialogflow_v2beta1/types/entity_type.py index 0b4b28b47..a4e0c4ad6 100644 --- a/google/cloud/dialogflow_v2beta1/types/entity_type.py +++ b/google/cloud/dialogflow_v2beta1/types/entity_type.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/environment.py b/google/cloud/dialogflow_v2beta1/types/environment.py index 1d75e958b..524c840b7 100644 --- a/google/cloud/dialogflow_v2beta1/types/environment.py +++ b/google/cloud/dialogflow_v2beta1/types/environment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/fulfillment.py b/google/cloud/dialogflow_v2beta1/types/fulfillment.py index 63f32ab5a..ca77923d5 100644 --- a/google/cloud/dialogflow_v2beta1/types/fulfillment.py +++ b/google/cloud/dialogflow_v2beta1/types/fulfillment.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/gcs.py b/google/cloud/dialogflow_v2beta1/types/gcs.py index 55d3738a3..6098a98ba 100644 --- a/google/cloud/dialogflow_v2beta1/types/gcs.py +++ b/google/cloud/dialogflow_v2beta1/types/gcs.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/human_agent_assistant_event.py b/google/cloud/dialogflow_v2beta1/types/human_agent_assistant_event.py index 92d9719b5..2217caf0d 100644 --- a/google/cloud/dialogflow_v2beta1/types/human_agent_assistant_event.py +++ b/google/cloud/dialogflow_v2beta1/types/human_agent_assistant_event.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/intent.py b/google/cloud/dialogflow_v2beta1/types/intent.py index 27ce52376..724a044a6 100644 --- a/google/cloud/dialogflow_v2beta1/types/intent.py +++ b/google/cloud/dialogflow_v2beta1/types/intent.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/knowledge_base.py b/google/cloud/dialogflow_v2beta1/types/knowledge_base.py index 5ef3c439e..62cd83515 100644 --- a/google/cloud/dialogflow_v2beta1/types/knowledge_base.py +++ b/google/cloud/dialogflow_v2beta1/types/knowledge_base.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/participant.py b/google/cloud/dialogflow_v2beta1/types/participant.py index 88d4b09cf..cc52ee917 100644 --- a/google/cloud/dialogflow_v2beta1/types/participant.py +++ b/google/cloud/dialogflow_v2beta1/types/participant.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/session.py b/google/cloud/dialogflow_v2beta1/types/session.py index d0818ba01..78469185c 100644 --- a/google/cloud/dialogflow_v2beta1/types/session.py +++ b/google/cloud/dialogflow_v2beta1/types/session.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import duration_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/session_entity_type.py b/google/cloud/dialogflow_v2beta1/types/session_entity_type.py index 72a569c75..f0e741039 100644 --- a/google/cloud/dialogflow_v2beta1/types/session_entity_type.py +++ b/google/cloud/dialogflow_v2beta1/types/session_entity_type.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/validation_result.py b/google/cloud/dialogflow_v2beta1/types/validation_result.py index 1f4fc3e98..a3b82c49f 100644 --- a/google/cloud/dialogflow_v2beta1/types/validation_result.py +++ b/google/cloud/dialogflow_v2beta1/types/validation_result.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence import proto # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/version.py b/google/cloud/dialogflow_v2beta1/types/version.py index 17e90708c..82b6249ba 100644 --- a/google/cloud/dialogflow_v2beta1/types/version.py +++ b/google/cloud/dialogflow_v2beta1/types/version.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import field_mask_pb2 # type: ignore diff --git a/google/cloud/dialogflow_v2beta1/types/webhook.py b/google/cloud/dialogflow_v2beta1/types/webhook.py index 66ba240ec..d35583048 100644 --- a/google/cloud/dialogflow_v2beta1/types/webhook.py +++ b/google/cloud/dialogflow_v2beta1/types/webhook.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + from typing import MutableMapping, MutableSequence from google.protobuf import struct_pb2 # type: ignore diff --git a/scripts/fixup_dialogflow_v2_keywords.py b/scripts/fixup_dialogflow_v2_keywords.py index 38e0d0e7f..0822b56f0 100644 --- a/scripts/fixup_dialogflow_v2_keywords.py +++ b/scripts/fixup_dialogflow_v2_keywords.py @@ -125,7 +125,7 @@ class dialogflowCallTransformer(cst.CSTTransformer): 'streaming_analyze_content': ('participant', 'audio_config', 'text_config', 'reply_audio_config', 'input_audio', 'input_text', 'input_dtmf', 'query_params', 'assist_query_params', 'cx_parameters', 'enable_partial_automated_agent_reply', ), 'streaming_detect_intent': ('session', 'query_input', 'query_params', 'single_utterance', 'output_audio_config', 'output_audio_config_mask', 'input_audio', ), 'suggest_articles': ('parent', 'latest_message', 'context_size', 'assist_query_params', ), - 'suggest_conversation_summary': ('conversation', 'latest_message', 'context_size', ), + 'suggest_conversation_summary': ('conversation', 'latest_message', 'context_size', 'assist_query_params', ), 'suggest_faq_answers': ('parent', 'latest_message', 'context_size', 'assist_query_params', ), 'suggest_smart_replies': ('parent', 'current_text_input', 'latest_message', 'context_size', ), 'train_agent': ('parent', ), diff --git a/tests/unit/gapic/dialogflow_v2/test_agents.py b/tests/unit/gapic/dialogflow_v2/test_agents.py index 0a08c2156..d06c421c1 100644 --- a/tests/unit/gapic/dialogflow_v2/test_agents.py +++ b/tests/unit/gapic/dialogflow_v2/test_agents.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -44,12 +46,15 @@ from google.oauth2 import service_account from google.protobuf import empty_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.agents import ( AgentsAsyncClient, @@ -105,6 +110,7 @@ def test__get_default_mtls_endpoint(): [ (AgentsClient, "grpc"), (AgentsAsyncClient, "grpc_asyncio"), + (AgentsClient, "rest"), ], ) def test_agents_client_from_service_account_info(client_class, transport_name): @@ -118,7 +124,11 @@ def test_agents_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -126,6 +136,7 @@ def test_agents_client_from_service_account_info(client_class, transport_name): [ (transports.AgentsGrpcTransport, "grpc"), (transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.AgentsRestTransport, "rest"), ], ) def test_agents_client_service_account_always_use_jwt(transport_class, transport_name): @@ -149,6 +160,7 @@ def test_agents_client_service_account_always_use_jwt(transport_class, transport [ (AgentsClient, "grpc"), (AgentsAsyncClient, "grpc_asyncio"), + (AgentsClient, "rest"), ], ) def test_agents_client_from_service_account_file(client_class, transport_name): @@ -169,13 +181,18 @@ def test_agents_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_agents_client_get_transport_class(): transport = AgentsClient.get_transport_class() available_transports = [ transports.AgentsGrpcTransport, + transports.AgentsRestTransport, ] assert transport in available_transports @@ -188,6 +205,7 @@ def test_agents_client_get_transport_class(): [ (AgentsClient, transports.AgentsGrpcTransport, "grpc"), (AgentsAsyncClient, transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (AgentsClient, transports.AgentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -327,6 +345,8 @@ def test_agents_client_client_options(client_class, transport_class, transport_n "grpc_asyncio", "false", ), + (AgentsClient, transports.AgentsRestTransport, "rest", "true"), + (AgentsClient, transports.AgentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -512,6 +532,7 @@ def test_agents_client_get_mtls_endpoint_and_cert_source(client_class): [ (AgentsClient, transports.AgentsGrpcTransport, "grpc"), (AgentsAsyncClient, transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (AgentsClient, transports.AgentsRestTransport, "rest"), ], ) def test_agents_client_client_options_scopes( @@ -547,6 +568,7 @@ def test_agents_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (AgentsClient, transports.AgentsRestTransport, "rest", None), ], ) def test_agents_client_client_options_credentials_file( @@ -2741,169 +2763,2481 @@ async def test_get_validation_result_field_headers_async(): ) in kw["metadata"] -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.AgentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + agent.GetAgentRequest, + dict, + ], +) +def test_get_agent_rest(request_type): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = AgentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = agent.Agent( + parent="parent_value", + display_name="display_name_value", + default_language_code="default_language_code_value", + supported_language_codes=["supported_language_codes_value"], + time_zone="time_zone_value", + description="description_value", + avatar_uri="avatar_uri_value", + enable_logging=True, + match_mode=agent.Agent.MatchMode.MATCH_MODE_HYBRID, + classification_threshold=0.25520000000000004, + api_version=agent.Agent.ApiVersion.API_VERSION_V1, + tier=agent.Agent.Tier.TIER_STANDARD, ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.Agent) + assert response.parent == "parent_value" + assert response.display_name == "display_name_value" + assert response.default_language_code == "default_language_code_value" + assert response.supported_language_codes == ["supported_language_codes_value"] + assert response.time_zone == "time_zone_value" + assert response.description == "description_value" + assert response.avatar_uri == "avatar_uri_value" + assert response.enable_logging is True + assert response.match_mode == agent.Agent.MatchMode.MATCH_MODE_HYBRID + assert math.isclose( + response.classification_threshold, 0.25520000000000004, rel_tol=1e-6 ) - with pytest.raises(ValueError): - client = AgentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + assert response.api_version == agent.Agent.ApiVersion.API_VERSION_V1 + assert response.tier == agent.Agent.Tier.TIER_STANDARD + + +def test_get_agent_rest_required_fields(request_type=agent.GetAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.AgentsGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.Agent() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = AgentsClient( - client_options=options, - transport=transport, - ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = AgentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + unset_fields = transport.get_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) - # It is an error to provide scopes and a transport instance. - transport = transports.AgentsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), ) - with pytest.raises(ValueError): - client = AgentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AgentsRestInterceptor, "post_get_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_get_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.GetAgentRequest.pb(agent.GetAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = agent.Agent.to_json(agent.Agent()) + + request = agent.GetAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.Agent() + + client.get_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) + pre.assert_called_once() + post.assert_called_once() -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.AgentsGrpcTransport( + +def test_get_agent_rest_bad_request( + transport: str = "rest", request_type=agent.GetAgentRequest +): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = AgentsClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.AgentsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_agent(request) + + +def test_get_agent_rest_flattened(): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.AgentsGrpcAsyncIOTransport( + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = agent.Agent() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_agent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/agent" % client.transport._host, args[1] + ) + + +def test_get_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_agent( + agent.GetAgentRequest(), + parent="parent_value", + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.AgentsGrpcTransport, - transports.AgentsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() +def test_get_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + gcd_agent.SetAgentRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = AgentsClient.get_transport_class(transport_name)( +def test_set_agent_rest(request_type): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"agent": {"parent": "projects/sample1"}} + request_init["agent"] = { + "parent": "projects/sample1", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "enable_logging": True, + "match_mode": 1, + "classification_threshold": 0.25520000000000004, + "api_version": 1, + "tier": 1, + } + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_agent.Agent( + parent="parent_value", + display_name="display_name_value", + default_language_code="default_language_code_value", + supported_language_codes=["supported_language_codes_value"], + time_zone="time_zone_value", + description="description_value", + avatar_uri="avatar_uri_value", + enable_logging=True, + match_mode=gcd_agent.Agent.MatchMode.MATCH_MODE_HYBRID, + classification_threshold=0.25520000000000004, + api_version=gcd_agent.Agent.ApiVersion.API_VERSION_V1, + tier=gcd_agent.Agent.Tier.TIER_STANDARD, + ) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. - client = AgentsClient( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.AgentsGrpcTransport, + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.set_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_agent.Agent) + assert response.parent == "parent_value" + assert response.display_name == "display_name_value" + assert response.default_language_code == "default_language_code_value" + assert response.supported_language_codes == ["supported_language_codes_value"] + assert response.time_zone == "time_zone_value" + assert response.description == "description_value" + assert response.avatar_uri == "avatar_uri_value" + assert response.enable_logging is True + assert response.match_mode == gcd_agent.Agent.MatchMode.MATCH_MODE_HYBRID + assert math.isclose( + response.classification_threshold, 0.25520000000000004, rel_tol=1e-6 ) + assert response.api_version == gcd_agent.Agent.ApiVersion.API_VERSION_V1 + assert response.tier == gcd_agent.Agent.Tier.TIER_STANDARD -def test_agents_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.AgentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +def test_set_agent_rest_required_fields(request_type=gcd_agent.SetAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) + # verify fields with default values are dropped -def test_agents_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.agents.transports.AgentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.AgentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).set_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "get_agent", - "set_agent", - "delete_agent", - "search_agents", - "train_agent", - "export_agent", - "import_agent", - "restore_agent", - "get_validation_result", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + # verify required fields with default values are now present - with pytest.raises(NotImplementedError): - transport.close() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).set_agent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client + # verify required fields with non-default values are left alone + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_agent.Agent() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.set_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_set_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.set_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("agent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_set_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AgentsRestInterceptor, "post_set_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_set_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_agent.SetAgentRequest.pb(gcd_agent.SetAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_agent.Agent.to_json(gcd_agent.Agent()) + + request = gcd_agent.SetAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_agent.Agent() + + client.set_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_set_agent_rest_bad_request( + transport: str = "rest", request_type=gcd_agent.SetAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"agent": {"parent": "projects/sample1"}} + request_init["agent"] = { + "parent": "projects/sample1", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "enable_logging": True, + "match_mode": 1, + "classification_threshold": 0.25520000000000004, + "api_version": 1, + "tier": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.set_agent(request) + + +def test_set_agent_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_agent.Agent() + + # get arguments that satisfy an http rule for this method + sample_request = {"agent": {"parent": "projects/sample1"}} + + # get truthy value for each flattened field + mock_args = dict( + agent=gcd_agent.Agent(parent="parent_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.set_agent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{agent.parent=projects/*}/agent" % client.transport._host, args[1] + ) + + +def test_set_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.set_agent( + gcd_agent.SetAgentRequest(), + agent=gcd_agent.Agent(parent="parent_value"), + ) + + +def test_set_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.DeleteAgentRequest, + dict, + ], +) +def test_delete_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_agent(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_agent_rest_required_fields(request_type=agent.DeleteAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AgentsRestInterceptor, "pre_delete_agent" + ) as pre: + pre.assert_not_called() + pb_message = agent.DeleteAgentRequest.pb(agent.DeleteAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = agent.DeleteAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_agent_rest_bad_request( + transport: str = "rest", request_type=agent.DeleteAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_agent(request) + + +def test_delete_agent_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_agent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/agent" % client.transport._host, args[1] + ) + + +def test_delete_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_agent( + agent.DeleteAgentRequest(), + parent="parent_value", + ) + + +def test_delete_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.SearchAgentsRequest, + dict, + ], +) +def test_search_agents_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = agent.SearchAgentsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.SearchAgentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.search_agents(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.SearchAgentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_search_agents_rest_required_fields(request_type=agent.SearchAgentsRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_agents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_agents._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.SearchAgentsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = agent.SearchAgentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.search_agents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_search_agents_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.search_agents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_search_agents_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AgentsRestInterceptor, "post_search_agents" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_search_agents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.SearchAgentsRequest.pb(agent.SearchAgentsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = agent.SearchAgentsResponse.to_json( + agent.SearchAgentsResponse() + ) + + request = agent.SearchAgentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.SearchAgentsResponse() + + client.search_agents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_search_agents_rest_bad_request( + transport: str = "rest", request_type=agent.SearchAgentsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.search_agents(request) + + +def test_search_agents_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = agent.SearchAgentsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.SearchAgentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.search_agents(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/agent:search" % client.transport._host, args[1] + ) + + +def test_search_agents_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.search_agents( + agent.SearchAgentsRequest(), + parent="parent_value", + ) + + +def test_search_agents_rest_pager(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + agent.SearchAgentsResponse( + agents=[ + agent.Agent(), + agent.Agent(), + agent.Agent(), + ], + next_page_token="abc", + ), + agent.SearchAgentsResponse( + agents=[], + next_page_token="def", + ), + agent.SearchAgentsResponse( + agents=[ + agent.Agent(), + ], + next_page_token="ghi", + ), + agent.SearchAgentsResponse( + agents=[ + agent.Agent(), + agent.Agent(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(agent.SearchAgentsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1"} + + pager = client.search_agents(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, agent.Agent) for i in results) + + pages = list(client.search_agents(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + agent.TrainAgentRequest, + dict, + ], +) +def test_train_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.train_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_train_agent_rest_required_fields(request_type=agent.TrainAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).train_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).train_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.train_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_train_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.train_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_train_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.AgentsRestInterceptor, "post_train_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_train_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.TrainAgentRequest.pb(agent.TrainAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = agent.TrainAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.train_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_train_agent_rest_bad_request( + transport: str = "rest", request_type=agent.TrainAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.train_agent(request) + + +def test_train_agent_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.train_agent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/agent:train" % client.transport._host, args[1] + ) + + +def test_train_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.train_agent( + agent.TrainAgentRequest(), + parent="parent_value", + ) + + +def test_train_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.ExportAgentRequest, + dict, + ], +) +def test_export_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.export_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_export_agent_rest_required_fields(request_type=agent.ExportAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["agent_uri"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).export_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + jsonified_request["agentUri"] = "agent_uri_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).export_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + assert "agentUri" in jsonified_request + assert jsonified_request["agentUri"] == "agent_uri_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.export_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_export_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.export_agent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "agentUri", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_export_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.AgentsRestInterceptor, "post_export_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_export_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.ExportAgentRequest.pb(agent.ExportAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = agent.ExportAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.export_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_export_agent_rest_bad_request( + transport: str = "rest", request_type=agent.ExportAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.export_agent(request) + + +def test_export_agent_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.export_agent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/agent:export" % client.transport._host, args[1] + ) + + +def test_export_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.export_agent( + agent.ExportAgentRequest(), + parent="parent_value", + ) + + +def test_export_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.ImportAgentRequest, + dict, + ], +) +def test_import_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.import_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_import_agent_rest_required_fields(request_type=agent.ImportAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).import_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).import_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.import_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_import_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.import_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_import_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.AgentsRestInterceptor, "post_import_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_import_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.ImportAgentRequest.pb(agent.ImportAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = agent.ImportAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.import_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_import_agent_rest_bad_request( + transport: str = "rest", request_type=agent.ImportAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.import_agent(request) + + +def test_import_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.RestoreAgentRequest, + dict, + ], +) +def test_restore_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.restore_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_restore_agent_rest_required_fields(request_type=agent.RestoreAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).restore_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).restore_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.restore_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_restore_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.restore_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_restore_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.AgentsRestInterceptor, "post_restore_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_restore_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.RestoreAgentRequest.pb(agent.RestoreAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = agent.RestoreAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.restore_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_restore_agent_rest_bad_request( + transport: str = "rest", request_type=agent.RestoreAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.restore_agent(request) + + +def test_restore_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.GetValidationResultRequest, + dict, + ], +) +def test_get_validation_result_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = validation_result.ValidationResult() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = validation_result.ValidationResult.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_validation_result(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, validation_result.ValidationResult) + + +def test_get_validation_result_rest_required_fields( + request_type=agent.GetValidationResultRequest, +): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_validation_result._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_validation_result._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = validation_result.ValidationResult() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = validation_result.ValidationResult.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_validation_result(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_validation_result_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_validation_result._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_validation_result_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AgentsRestInterceptor, "post_get_validation_result" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_get_validation_result" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.GetValidationResultRequest.pb( + agent.GetValidationResultRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = validation_result.ValidationResult.to_json( + validation_result.ValidationResult() + ) + + request = agent.GetValidationResultRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = validation_result.ValidationResult() + + client.get_validation_result( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_validation_result_rest_bad_request( + transport: str = "rest", request_type=agent.GetValidationResultRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_validation_result(request) + + +def test_get_validation_result_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = AgentsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = AgentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = AgentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.AgentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AgentsGrpcTransport, + transports.AgentsGrpcAsyncIOTransport, + transports.AgentsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = AgentsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.AgentsGrpcTransport, + ) + + +def test_agents_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.AgentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_agents_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.agents.transports.AgentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.AgentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "get_agent", + "set_agent", + "delete_agent", + "search_agents", + "train_agent", + "export_agent", + "import_agent", + "restore_agent", + "get_validation_result", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client # Catch all for all remaining methods and properties remainder = [ @@ -2992,6 +5326,7 @@ def test_agents_transport_auth_adc(transport_class): [ transports.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport, + transports.AgentsRestTransport, ], ) def test_agents_transport_auth_gdch_credentials(transport_class): @@ -3089,11 +5424,40 @@ def test_agents_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_agents_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.AgentsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_agents_rest_lro_client(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_agents_host_no_port(transport_name): @@ -3104,7 +5468,11 @@ def test_agents_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3112,6 +5480,7 @@ def test_agents_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_agents_host_with_port(transport_name): @@ -3122,7 +5491,57 @@ def test_agents_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_agents_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = AgentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = AgentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.get_agent._session + session2 = client2.transport.get_agent._session + assert session1 != session2 + session1 = client1.transport.set_agent._session + session2 = client2.transport.set_agent._session + assert session1 != session2 + session1 = client1.transport.delete_agent._session + session2 = client2.transport.delete_agent._session + assert session1 != session2 + session1 = client1.transport.search_agents._session + session2 = client2.transport.search_agents._session + assert session1 != session2 + session1 = client1.transport.train_agent._session + session2 = client2.transport.train_agent._session + assert session1 != session2 + session1 = client1.transport.export_agent._session + session2 = client2.transport.export_agent._session + assert session1 != session2 + session1 = client1.transport.import_agent._session + session2 = client2.transport.import_agent._session + assert session1 != session2 + session1 = client1.transport.restore_agent._session + session2 = client2.transport.restore_agent._session + assert session1 != session2 + session1 = client1.transport.get_validation_result._session + session2 = client2.transport.get_validation_result._session + assert session1 != session2 def test_agents_grpc_transport_channel(): @@ -3437,6 +5856,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4154,6 +6859,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4171,6 +6877,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_answer_records.py b/tests/unit/gapic/dialogflow_v2/test_answer_records.py index b31c3954f..79b95416a 100644 --- a/tests/unit/gapic/dialogflow_v2/test_answer_records.py +++ b/tests/unit/gapic/dialogflow_v2/test_answer_records.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,12 +36,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.answer_records import ( AnswerRecordsAsyncClient, @@ -101,6 +106,7 @@ def test__get_default_mtls_endpoint(): [ (AnswerRecordsClient, "grpc"), (AnswerRecordsAsyncClient, "grpc_asyncio"), + (AnswerRecordsClient, "rest"), ], ) def test_answer_records_client_from_service_account_info(client_class, transport_name): @@ -114,7 +120,11 @@ def test_answer_records_client_from_service_account_info(client_class, transport assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -122,6 +132,7 @@ def test_answer_records_client_from_service_account_info(client_class, transport [ (transports.AnswerRecordsGrpcTransport, "grpc"), (transports.AnswerRecordsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.AnswerRecordsRestTransport, "rest"), ], ) def test_answer_records_client_service_account_always_use_jwt( @@ -147,6 +158,7 @@ def test_answer_records_client_service_account_always_use_jwt( [ (AnswerRecordsClient, "grpc"), (AnswerRecordsAsyncClient, "grpc_asyncio"), + (AnswerRecordsClient, "rest"), ], ) def test_answer_records_client_from_service_account_file(client_class, transport_name): @@ -167,13 +179,18 @@ def test_answer_records_client_from_service_account_file(client_class, transport assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_answer_records_client_get_transport_class(): transport = AnswerRecordsClient.get_transport_class() available_transports = [ transports.AnswerRecordsGrpcTransport, + transports.AnswerRecordsRestTransport, ] assert transport in available_transports @@ -190,6 +207,7 @@ def test_answer_records_client_get_transport_class(): transports.AnswerRecordsGrpcAsyncIOTransport, "grpc_asyncio", ), + (AnswerRecordsClient, transports.AnswerRecordsRestTransport, "rest"), ], ) @mock.patch.object( @@ -335,6 +353,8 @@ def test_answer_records_client_client_options( "grpc_asyncio", "false", ), + (AnswerRecordsClient, transports.AnswerRecordsRestTransport, "rest", "true"), + (AnswerRecordsClient, transports.AnswerRecordsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -534,6 +554,7 @@ def test_answer_records_client_get_mtls_endpoint_and_cert_source(client_class): transports.AnswerRecordsGrpcAsyncIOTransport, "grpc_asyncio", ), + (AnswerRecordsClient, transports.AnswerRecordsRestTransport, "rest"), ], ) def test_answer_records_client_client_options_scopes( @@ -574,6 +595,7 @@ def test_answer_records_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (AnswerRecordsClient, transports.AnswerRecordsRestTransport, "rest", None), ], ) def test_answer_records_client_client_options_credentials_file( @@ -1391,6 +1413,703 @@ async def test_update_answer_record_flattened_error_async(): ) +@pytest.mark.parametrize( + "request_type", + [ + answer_record.ListAnswerRecordsRequest, + dict, + ], +) +def test_list_answer_records_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = answer_record.ListAnswerRecordsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = answer_record.ListAnswerRecordsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_answer_records(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListAnswerRecordsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_answer_records_rest_required_fields( + request_type=answer_record.ListAnswerRecordsRequest, +): + transport_class = transports.AnswerRecordsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_answer_records._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_answer_records._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "filter", + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = answer_record.ListAnswerRecordsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = answer_record.ListAnswerRecordsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_answer_records(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_answer_records_rest_unset_required_fields(): + transport = transports.AnswerRecordsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_answer_records._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_answer_records_rest_interceptors(null_interceptor): + transport = transports.AnswerRecordsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AnswerRecordsRestInterceptor(), + ) + client = AnswerRecordsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AnswerRecordsRestInterceptor, "post_list_answer_records" + ) as post, mock.patch.object( + transports.AnswerRecordsRestInterceptor, "pre_list_answer_records" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = answer_record.ListAnswerRecordsRequest.pb( + answer_record.ListAnswerRecordsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = answer_record.ListAnswerRecordsResponse.to_json( + answer_record.ListAnswerRecordsResponse() + ) + + request = answer_record.ListAnswerRecordsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = answer_record.ListAnswerRecordsResponse() + + client.list_answer_records( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_answer_records_rest_bad_request( + transport: str = "rest", request_type=answer_record.ListAnswerRecordsRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_answer_records(request) + + +def test_list_answer_records_rest_flattened(): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = answer_record.ListAnswerRecordsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = answer_record.ListAnswerRecordsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_answer_records(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/answerRecords" % client.transport._host, args[1] + ) + + +def test_list_answer_records_rest_flattened_error(transport: str = "rest"): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_answer_records( + answer_record.ListAnswerRecordsRequest(), + parent="parent_value", + ) + + +def test_list_answer_records_rest_pager(transport: str = "rest"): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + answer_record.ListAnswerRecordsResponse( + answer_records=[ + answer_record.AnswerRecord(), + answer_record.AnswerRecord(), + answer_record.AnswerRecord(), + ], + next_page_token="abc", + ), + answer_record.ListAnswerRecordsResponse( + answer_records=[], + next_page_token="def", + ), + answer_record.ListAnswerRecordsResponse( + answer_records=[ + answer_record.AnswerRecord(), + ], + next_page_token="ghi", + ), + answer_record.ListAnswerRecordsResponse( + answer_records=[ + answer_record.AnswerRecord(), + answer_record.AnswerRecord(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + answer_record.ListAnswerRecordsResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1"} + + pager = client.list_answer_records(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, answer_record.AnswerRecord) for i in results) + + pages = list(client.list_answer_records(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_answer_record.UpdateAnswerRecordRequest, + dict, + ], +) +def test_update_answer_record_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"answer_record": {"name": "projects/sample1/answerRecords/sample2"}} + request_init["answer_record"] = { + "name": "projects/sample1/answerRecords/sample2", + "answer_feedback": { + "correctness_level": 1, + "agent_assistant_detail_feedback": { + "answer_relevance": 1, + "document_correctness": 1, + "document_efficiency": 1, + "summarization_feedback": { + "start_time": {"seconds": 751, "nanos": 543}, + "submit_time": {}, + "summary_text": "summary_text_value", + }, + }, + "clicked": True, + "click_time": {}, + "displayed": True, + "display_time": {}, + }, + "agent_assistant_record": { + "article_suggestion_answer": { + "title": "title_value", + "uri": "uri_value", + "snippets": ["snippets_value1", "snippets_value2"], + "confidence": 0.1038, + "metadata": {}, + "answer_record": "answer_record_value", + }, + "faq_answer": { + "answer": "answer_value", + "confidence": 0.1038, + "question": "question_value", + "source": "source_value", + "metadata": {}, + "answer_record": "answer_record_value", + }, + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_answer_record.AnswerRecord( + name="name_value", + agent_assistant_record=gcd_answer_record.AgentAssistantRecord( + article_suggestion_answer=participant.ArticleAnswer(title="title_value") + ), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_answer_record.AnswerRecord.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_answer_record(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_answer_record.AnswerRecord) + assert response.name == "name_value" + + +def test_update_answer_record_rest_required_fields( + request_type=gcd_answer_record.UpdateAnswerRecordRequest, +): + transport_class = transports.AnswerRecordsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_answer_record._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_answer_record._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_answer_record.AnswerRecord() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_answer_record.AnswerRecord.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_answer_record(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_answer_record_rest_unset_required_fields(): + transport = transports.AnswerRecordsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_answer_record._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "answerRecord", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_answer_record_rest_interceptors(null_interceptor): + transport = transports.AnswerRecordsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AnswerRecordsRestInterceptor(), + ) + client = AnswerRecordsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AnswerRecordsRestInterceptor, "post_update_answer_record" + ) as post, mock.patch.object( + transports.AnswerRecordsRestInterceptor, "pre_update_answer_record" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_answer_record.UpdateAnswerRecordRequest.pb( + gcd_answer_record.UpdateAnswerRecordRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_answer_record.AnswerRecord.to_json( + gcd_answer_record.AnswerRecord() + ) + + request = gcd_answer_record.UpdateAnswerRecordRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_answer_record.AnswerRecord() + + client.update_answer_record( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_answer_record_rest_bad_request( + transport: str = "rest", request_type=gcd_answer_record.UpdateAnswerRecordRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"answer_record": {"name": "projects/sample1/answerRecords/sample2"}} + request_init["answer_record"] = { + "name": "projects/sample1/answerRecords/sample2", + "answer_feedback": { + "correctness_level": 1, + "agent_assistant_detail_feedback": { + "answer_relevance": 1, + "document_correctness": 1, + "document_efficiency": 1, + "summarization_feedback": { + "start_time": {"seconds": 751, "nanos": 543}, + "submit_time": {}, + "summary_text": "summary_text_value", + }, + }, + "clicked": True, + "click_time": {}, + "displayed": True, + "display_time": {}, + }, + "agent_assistant_record": { + "article_suggestion_answer": { + "title": "title_value", + "uri": "uri_value", + "snippets": ["snippets_value1", "snippets_value2"], + "confidence": 0.1038, + "metadata": {}, + "answer_record": "answer_record_value", + }, + "faq_answer": { + "answer": "answer_value", + "confidence": 0.1038, + "question": "question_value", + "source": "source_value", + "metadata": {}, + "answer_record": "answer_record_value", + }, + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_answer_record(request) + + +def test_update_answer_record_rest_flattened(): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_answer_record.AnswerRecord() + + # get arguments that satisfy an http rule for this method + sample_request = { + "answer_record": {"name": "projects/sample1/answerRecords/sample2"} + } + + # get truthy value for each flattened field + mock_args = dict( + answer_record=gcd_answer_record.AnswerRecord(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_answer_record.AnswerRecord.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_answer_record(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{answer_record.name=projects/*/answerRecords/*}" + % client.transport._host, + args[1], + ) + + +def test_update_answer_record_rest_flattened_error(transport: str = "rest"): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_answer_record( + gcd_answer_record.UpdateAnswerRecordRequest(), + answer_record=gcd_answer_record.AnswerRecord(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_answer_record_rest_error(): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.AnswerRecordsGrpcTransport( @@ -1472,6 +2191,7 @@ def test_transport_get_channel(): [ transports.AnswerRecordsGrpcTransport, transports.AnswerRecordsGrpcAsyncIOTransport, + transports.AnswerRecordsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1486,6 +2206,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1630,6 +2351,7 @@ def test_answer_records_transport_auth_adc(transport_class): [ transports.AnswerRecordsGrpcTransport, transports.AnswerRecordsGrpcAsyncIOTransport, + transports.AnswerRecordsRestTransport, ], ) def test_answer_records_transport_auth_gdch_credentials(transport_class): @@ -1730,11 +2452,23 @@ def test_answer_records_grpc_transport_client_cert_source_for_mtls(transport_cla ) +def test_answer_records_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.AnswerRecordsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_answer_records_host_no_port(transport_name): @@ -1745,7 +2479,11 @@ def test_answer_records_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1753,6 +2491,7 @@ def test_answer_records_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_answer_records_host_with_port(transport_name): @@ -1763,7 +2502,36 @@ def test_answer_records_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_answer_records_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = AnswerRecordsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = AnswerRecordsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_answer_records._session + session2 = client2.transport.list_answer_records._session + assert session1 != session2 + session1 = client1.transport.update_answer_record._session + session2 = client2.transport.update_answer_record._session + assert session1 != session2 def test_answer_records_grpc_transport_channel(): @@ -2053,6 +2821,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = AnswerRecordsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2770,6 +3824,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2787,6 +3842,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_contexts.py b/tests/unit/gapic/dialogflow_v2/test_contexts.py index 3cd58a5b6..53d7f9709 100644 --- a/tests/unit/gapic/dialogflow_v2/test_contexts.py +++ b/tests/unit/gapic/dialogflow_v2/test_contexts.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,12 +36,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.contexts import ( ContextsAsyncClient, @@ -95,6 +100,7 @@ def test__get_default_mtls_endpoint(): [ (ContextsClient, "grpc"), (ContextsAsyncClient, "grpc_asyncio"), + (ContextsClient, "rest"), ], ) def test_contexts_client_from_service_account_info(client_class, transport_name): @@ -108,7 +114,11 @@ def test_contexts_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -116,6 +126,7 @@ def test_contexts_client_from_service_account_info(client_class, transport_name) [ (transports.ContextsGrpcTransport, "grpc"), (transports.ContextsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ContextsRestTransport, "rest"), ], ) def test_contexts_client_service_account_always_use_jwt( @@ -141,6 +152,7 @@ def test_contexts_client_service_account_always_use_jwt( [ (ContextsClient, "grpc"), (ContextsAsyncClient, "grpc_asyncio"), + (ContextsClient, "rest"), ], ) def test_contexts_client_from_service_account_file(client_class, transport_name): @@ -161,13 +173,18 @@ def test_contexts_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_contexts_client_get_transport_class(): transport = ContextsClient.get_transport_class() available_transports = [ transports.ContextsGrpcTransport, + transports.ContextsRestTransport, ] assert transport in available_transports @@ -180,6 +197,7 @@ def test_contexts_client_get_transport_class(): [ (ContextsClient, transports.ContextsGrpcTransport, "grpc"), (ContextsAsyncClient, transports.ContextsGrpcAsyncIOTransport, "grpc_asyncio"), + (ContextsClient, transports.ContextsRestTransport, "rest"), ], ) @mock.patch.object( @@ -321,6 +339,8 @@ def test_contexts_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (ContextsClient, transports.ContextsRestTransport, "rest", "true"), + (ContextsClient, transports.ContextsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -510,6 +530,7 @@ def test_contexts_client_get_mtls_endpoint_and_cert_source(client_class): [ (ContextsClient, transports.ContextsGrpcTransport, "grpc"), (ContextsAsyncClient, transports.ContextsGrpcAsyncIOTransport, "grpc_asyncio"), + (ContextsClient, transports.ContextsRestTransport, "rest"), ], ) def test_contexts_client_client_options_scopes( @@ -545,6 +566,7 @@ def test_contexts_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (ContextsClient, transports.ContextsRestTransport, "rest", None), ], ) def test_contexts_client_client_options_credentials_file( @@ -2243,175 +2265,1844 @@ async def test_delete_all_contexts_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ContextsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + context.ListContextsRequest, + dict, + ], +) +def test_list_contexts_rest(request_type): + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ContextsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = context.ListContextsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ContextsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = context.ListContextsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_contexts(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListContextsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_contexts_rest_required_fields(request_type=context.ListContextsRequest): + transport_class = transports.ContextsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_contexts._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_contexts._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ContextsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = context.ListContextsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = context.ListContextsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_contexts(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_contexts_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_contexts._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.ContextsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_contexts_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ContextsClient( - client_options=options, - transport=transport, + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "post_list_contexts" + ) as post, mock.patch.object( + transports.ContextsRestInterceptor, "pre_list_contexts" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = context.ListContextsRequest.pb(context.ListContextsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = context.ListContextsResponse.to_json( + context.ListContextsResponse() ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ContextsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = context.ListContextsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = context.ListContextsResponse() + + client.list_contexts( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.ContextsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_contexts_rest_bad_request( + transport: str = "rest", request_type=context.ListContextsRequest +): + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = ContextsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ContextsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_contexts(request) + + +def test_list_contexts_rest_flattened(): + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = ContextsClient(transport=transport) - assert client.transport is transport + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = context.ListContextsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ContextsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = context.ListContextsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_contexts(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent/sessions/*}/contexts" + % client.transport._host, + args[1], + ) + + +def test_list_contexts_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.ContextsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_contexts( + context.ListContextsRequest(), + parent="parent_value", + ) + + +def test_list_contexts_rest_pager(transport: str = "rest"): + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + context.ListContextsResponse( + contexts=[ + context.Context(), + context.Context(), + context.Context(), + ], + next_page_token="abc", + ), + context.ListContextsResponse( + contexts=[], + next_page_token="def", + ), + context.ListContextsResponse( + contexts=[ + context.Context(), + ], + next_page_token="ghi", + ), + context.ListContextsResponse( + contexts=[ + context.Context(), + context.Context(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(context.ListContextsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values -@pytest.mark.parametrize( - "transport_class", - [ - transports.ContextsGrpcTransport, - transports.ContextsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + pager = client.list_contexts(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, context.Context) for i in results) + + pages = list(client.list_contexts(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + context.GetContextRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = ContextsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name - - -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. +def test_get_context_rest(request_type): client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.ContextsGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + request = request_type(**request_init) -def test_contexts_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ContextsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = context.Context( + name="name_value", + lifespan_count=1498, ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_contexts_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.contexts.transports.ContextsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ContextsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_context(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_contexts", - "get_context", - "create_context", - "update_context", - "delete_context", - "delete_all_contexts", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + # Establish that the response is the type that we expect. + assert isinstance(response, context.Context) + assert response.name == "name_value" + assert response.lifespan_count == 1498 + + +def test_get_context_rest_required_fields(request_type=context.GetContextRequest): + transport_class = transports.ContextsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + # verify required fields with default values are now present -def test_contexts_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = context.Context() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_context(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_context_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_context._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_context_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), + ) + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "post_get_context" + ) as post, mock.patch.object( + transports.ContextsRestInterceptor, "pre_get_context" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = context.GetContextRequest.pb(context.GetContextRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = context.Context.to_json(context.Context()) + + request = context.GetContextRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = context.Context() + + client.get_context( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_context_rest_bad_request( + transport: str = "rest", request_type=context.GetContextRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_context(request) + + +def test_get_context_rest_flattened(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = context.Context() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/agent/sessions/sample2/contexts/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_context(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/agent/sessions/*/contexts/*}" + % client.transport._host, + args[1], + ) + + +def test_get_context_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_context( + context.GetContextRequest(), + name="name_value", + ) + + +def test_get_context_rest_error(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_context.CreateContextRequest, + dict, + ], +) +def test_create_context_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request_init["context"] = { + "name": "name_value", + "lifespan_count": 1498, + "parameters": {"fields": {}}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context( + name="name_value", + lifespan_count=1498, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_context(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_context.Context) + assert response.name == "name_value" + assert response.lifespan_count == 1498 + + +def test_create_context_rest_required_fields( + request_type=gcd_context.CreateContextRequest, +): + transport_class = transports.ContextsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_context(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_context_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_context._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "context", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_context_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), + ) + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "post_create_context" + ) as post, mock.patch.object( + transports.ContextsRestInterceptor, "pre_create_context" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_context.CreateContextRequest.pb( + gcd_context.CreateContextRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_context.Context.to_json(gcd_context.Context()) + + request = gcd_context.CreateContextRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_context.Context() + + client.create_context( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_context_rest_bad_request( + transport: str = "rest", request_type=gcd_context.CreateContextRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request_init["context"] = { + "name": "name_value", + "lifespan_count": 1498, + "parameters": {"fields": {}}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_context(request) + + +def test_create_context_rest_flattened(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + context=gcd_context.Context(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_context(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent/sessions/*}/contexts" + % client.transport._host, + args[1], + ) + + +def test_create_context_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_context( + gcd_context.CreateContextRequest(), + parent="parent_value", + context=gcd_context.Context(name="name_value"), + ) + + +def test_create_context_rest_error(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_context.UpdateContextRequest, + dict, + ], +) +def test_update_context_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "context": {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + } + request_init["context"] = { + "name": "projects/sample1/agent/sessions/sample2/contexts/sample3", + "lifespan_count": 1498, + "parameters": {"fields": {}}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context( + name="name_value", + lifespan_count=1498, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_context(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_context.Context) + assert response.name == "name_value" + assert response.lifespan_count == 1498 + + +def test_update_context_rest_required_fields( + request_type=gcd_context.UpdateContextRequest, +): + transport_class = transports.ContextsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_context._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_context(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_context_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_context._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("context",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_context_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), + ) + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "post_update_context" + ) as post, mock.patch.object( + transports.ContextsRestInterceptor, "pre_update_context" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_context.UpdateContextRequest.pb( + gcd_context.UpdateContextRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_context.Context.to_json(gcd_context.Context()) + + request = gcd_context.UpdateContextRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_context.Context() + + client.update_context( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_context_rest_bad_request( + transport: str = "rest", request_type=gcd_context.UpdateContextRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "context": {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + } + request_init["context"] = { + "name": "projects/sample1/agent/sessions/sample2/contexts/sample3", + "lifespan_count": 1498, + "parameters": {"fields": {}}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_context(request) + + +def test_update_context_rest_flattened(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context() + + # get arguments that satisfy an http rule for this method + sample_request = { + "context": { + "name": "projects/sample1/agent/sessions/sample2/contexts/sample3" + } + } + + # get truthy value for each flattened field + mock_args = dict( + context=gcd_context.Context(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_context(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{context.name=projects/*/agent/sessions/*/contexts/*}" + % client.transport._host, + args[1], + ) + + +def test_update_context_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_context( + gcd_context.UpdateContextRequest(), + context=gcd_context.Context(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_context_rest_error(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + context.DeleteContextRequest, + dict, + ], +) +def test_delete_context_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_context(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_context_rest_required_fields(request_type=context.DeleteContextRequest): + transport_class = transports.ContextsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_context(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_context_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_context._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_context_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), + ) + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "pre_delete_context" + ) as pre: + pre.assert_not_called() + pb_message = context.DeleteContextRequest.pb(context.DeleteContextRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = context.DeleteContextRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_context( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_context_rest_bad_request( + transport: str = "rest", request_type=context.DeleteContextRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_context(request) + + +def test_delete_context_rest_flattened(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/agent/sessions/sample2/contexts/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_context(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/agent/sessions/*/contexts/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_context_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_context( + context.DeleteContextRequest(), + name="name_value", + ) + + +def test_delete_context_rest_error(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + context.DeleteAllContextsRequest, + dict, + ], +) +def test_delete_all_contexts_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_all_contexts(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_all_contexts_rest_required_fields( + request_type=context.DeleteAllContextsRequest, +): + transport_class = transports.ContextsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_all_contexts._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_all_contexts._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_all_contexts(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_all_contexts_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_all_contexts._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_all_contexts_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), + ) + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "pre_delete_all_contexts" + ) as pre: + pre.assert_not_called() + pb_message = context.DeleteAllContextsRequest.pb( + context.DeleteAllContextsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = context.DeleteAllContextsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_all_contexts( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_all_contexts_rest_bad_request( + transport: str = "rest", request_type=context.DeleteAllContextsRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_all_contexts(request) + + +def test_delete_all_contexts_rest_flattened(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_all_contexts(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent/sessions/*}/contexts" + % client.transport._host, + args[1], + ) + + +def test_delete_all_contexts_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_all_contexts( + context.DeleteAllContextsRequest(), + parent="parent_value", + ) + + +def test_delete_all_contexts_rest_error(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ContextsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ContextsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ContextsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ContextsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ContextsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ContextsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ContextsGrpcTransport, + transports.ContextsGrpcAsyncIOTransport, + transports.ContextsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = ContextsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ContextsGrpcTransport, + ) + + +def test_contexts_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ContextsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_contexts_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.contexts.transports.ContextsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ContextsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_contexts", + "get_context", + "create_context", + "update_context", + "delete_context", + "delete_all_contexts", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_contexts_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True ) as load_creds, mock.patch( "google.cloud.dialogflow_v2.services.contexts.transports.ContextsTransport._prep_wrapped_messages" ) as Transport: @@ -2486,6 +4177,7 @@ def test_contexts_transport_auth_adc(transport_class): [ transports.ContextsGrpcTransport, transports.ContextsGrpcAsyncIOTransport, + transports.ContextsRestTransport, ], ) def test_contexts_transport_auth_gdch_credentials(transport_class): @@ -2583,11 +4275,23 @@ def test_contexts_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_contexts_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.ContextsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_contexts_host_no_port(transport_name): @@ -2598,7 +4302,11 @@ def test_contexts_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2606,6 +4314,7 @@ def test_contexts_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_contexts_host_with_port(transport_name): @@ -2616,7 +4325,48 @@ def test_contexts_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_contexts_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ContextsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ContextsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_contexts._session + session2 = client2.transport.list_contexts._session + assert session1 != session2 + session1 = client1.transport.get_context._session + session2 = client2.transport.get_context._session + assert session1 != session2 + session1 = client1.transport.create_context._session + session2 = client2.transport.create_context._session + assert session1 != session2 + session1 = client1.transport.update_context._session + session2 = client2.transport.update_context._session + assert session1 != session2 + session1 = client1.transport.delete_context._session + session2 = client2.transport.delete_context._session + assert session1 != session2 + session1 = client1.transport.delete_all_contexts._session + session2 = client2.transport.delete_all_contexts._session + assert session1 != session2 def test_contexts_grpc_transport_channel(): @@ -2903,6 +4653,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3620,6 +5656,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3637,6 +5674,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_conversation_datasets.py b/tests/unit/gapic/dialogflow_v2/test_conversation_datasets.py index 9a8fb53c4..58c5244ab 100644 --- a/tests/unit/gapic/dialogflow_v2/test_conversation_datasets.py +++ b/tests/unit/gapic/dialogflow_v2/test_conversation_datasets.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -43,12 +45,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import empty_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.conversation_datasets import ( ConversationDatasetsAsyncClient, @@ -113,6 +118,7 @@ def test__get_default_mtls_endpoint(): [ (ConversationDatasetsClient, "grpc"), (ConversationDatasetsAsyncClient, "grpc_asyncio"), + (ConversationDatasetsClient, "rest"), ], ) def test_conversation_datasets_client_from_service_account_info( @@ -128,7 +134,11 @@ def test_conversation_datasets_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -136,6 +146,7 @@ def test_conversation_datasets_client_from_service_account_info( [ (transports.ConversationDatasetsGrpcTransport, "grpc"), (transports.ConversationDatasetsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ConversationDatasetsRestTransport, "rest"), ], ) def test_conversation_datasets_client_service_account_always_use_jwt( @@ -161,6 +172,7 @@ def test_conversation_datasets_client_service_account_always_use_jwt( [ (ConversationDatasetsClient, "grpc"), (ConversationDatasetsAsyncClient, "grpc_asyncio"), + (ConversationDatasetsClient, "rest"), ], ) def test_conversation_datasets_client_from_service_account_file( @@ -183,13 +195,18 @@ def test_conversation_datasets_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_conversation_datasets_client_get_transport_class(): transport = ConversationDatasetsClient.get_transport_class() available_transports = [ transports.ConversationDatasetsGrpcTransport, + transports.ConversationDatasetsRestTransport, ] assert transport in available_transports @@ -210,6 +227,11 @@ def test_conversation_datasets_client_get_transport_class(): transports.ConversationDatasetsGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + ConversationDatasetsClient, + transports.ConversationDatasetsRestTransport, + "rest", + ), ], ) @mock.patch.object( @@ -365,6 +387,18 @@ def test_conversation_datasets_client_client_options( "grpc_asyncio", "false", ), + ( + ConversationDatasetsClient, + transports.ConversationDatasetsRestTransport, + "rest", + "true", + ), + ( + ConversationDatasetsClient, + transports.ConversationDatasetsRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -568,6 +602,11 @@ def test_conversation_datasets_client_get_mtls_endpoint_and_cert_source(client_c transports.ConversationDatasetsGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + ConversationDatasetsClient, + transports.ConversationDatasetsRestTransport, + "rest", + ), ], ) def test_conversation_datasets_client_client_options_scopes( @@ -608,6 +647,12 @@ def test_conversation_datasets_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + ConversationDatasetsClient, + transports.ConversationDatasetsRestTransport, + "rest", + None, + ), ], ) def test_conversation_datasets_client_client_options_credentials_file( @@ -2084,165 +2129,1582 @@ async def test_import_conversation_data_field_headers_async(): ) in kw["metadata"] -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ConversationDatasetsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation_dataset.CreateConversationDatasetRequest, + dict, + ], +) +def test_create_conversation_dataset_rest(request_type): + client = ConversationDatasetsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ConversationDatasetsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["conversation_dataset"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "create_time": {"seconds": 751, "nanos": 543}, + "input_config": {"gcs_source": {"uris": ["uris_value1", "uris_value2"]}}, + "conversation_info": {"language_code": "language_code_value"}, + "conversation_count": 1955, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_conversation_dataset(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_create_conversation_dataset_rest_required_fields( + request_type=gcd_conversation_dataset.CreateConversationDatasetRequest, +): + transport_class = transports.ConversationDatasetsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ConversationDatasetsGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation_dataset._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation_dataset._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationDatasetsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ConversationDatasetsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result - # It is an error to provide an api_key and a transport instance. - transport = transports.ConversationDatasetsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_conversation_dataset(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_conversation_dataset_rest_unset_required_fields(): + transport = transports.ConversationDatasetsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationDatasetsClient( - client_options=options, - transport=transport, - ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationDatasetsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + unset_fields = transport.create_conversation_dataset._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "conversationDataset", + ) ) + ) - # It is an error to provide scopes and a transport instance. - transport = transports.ConversationDatasetsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_conversation_dataset_rest_interceptors(null_interceptor): + transport = transports.ConversationDatasetsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationDatasetsRestInterceptor(), ) - with pytest.raises(ValueError): - client = ConversationDatasetsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = ConversationDatasetsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationDatasetsRestInterceptor, + "post_create_conversation_dataset", + ) as post, mock.patch.object( + transports.ConversationDatasetsRestInterceptor, + "pre_create_conversation_dataset", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation_dataset.CreateConversationDatasetRequest.pb( + gcd_conversation_dataset.CreateConversationDatasetRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() ) + request = gcd_conversation_dataset.CreateConversationDatasetRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationDatasetsGrpcTransport( + client.create_conversation_dataset( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_conversation_dataset_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation_dataset.CreateConversationDatasetRequest, +): + client = ConversationDatasetsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = ConversationDatasetsClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/locations/sample2"} + request_init["conversation_dataset"] = { + "name": "name_value", + "display_name": "display_name_value", + "description": "description_value", + "create_time": {"seconds": 751, "nanos": 543}, + "input_config": {"gcs_source": {"uris": ["uris_value1", "uris_value2"]}}, + "conversation_info": {"language_code": "language_code_value"}, + "conversation_count": 1955, + } + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationDatasetsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_conversation_dataset(request) + + +def test_create_conversation_dataset_rest_flattened(): + client = ConversationDatasetsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.ConversationDatasetsGrpcAsyncIOTransport( + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + conversation_dataset=gcd_conversation_dataset.ConversationDataset( + name="name_value" + ), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_conversation_dataset(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/locations/*}/conversationDatasets" + % client.transport._host, + args[1], + ) + + +def test_create_conversation_dataset_rest_flattened_error(transport: str = "rest"): + client = ConversationDatasetsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_conversation_dataset( + gcd_conversation_dataset.CreateConversationDatasetRequest(), + parent="parent_value", + conversation_dataset=gcd_conversation_dataset.ConversationDataset( + name="name_value" + ), + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.ConversationDatasetsGrpcTransport, - transports.ConversationDatasetsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + +def test_create_conversation_dataset_rest_error(): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + conversation_dataset.GetConversationDatasetRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = ConversationDatasetsClient.get_transport_class(transport_name)( +def test_get_conversation_dataset_rest(request_type): + client = ConversationDatasetsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationDatasets/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_dataset.ConversationDataset( + name="name_value", + display_name="display_name_value", + description="description_value", + conversation_count=1955, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_dataset.ConversationDataset.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_conversation_dataset(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, conversation_dataset.ConversationDataset) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.description == "description_value" + assert response.conversation_count == 1955 + + +def test_get_conversation_dataset_rest_required_fields( + request_type=conversation_dataset.GetConversationDatasetRequest, +): + transport_class = transports.ConversationDatasetsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation_dataset._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation_dataset._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = ConversationDatasetsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert isinstance( - client.transport, - transports.ConversationDatasetsGrpcTransport, - ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation_dataset.ConversationDataset() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + response_value = Response() + response_value.status_code = 200 -def test_conversation_datasets_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ConversationDatasetsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) + pb_return_value = conversation_dataset.ConversationDataset.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value -def test_conversation_datasets_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.conversation_datasets.transports.ConversationDatasetsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ConversationDatasetsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response = client.get_conversation_dataset(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "create_conversation_dataset", - "get_conversation_dataset", - "list_conversation_datasets", - "delete_conversation_dataset", - "import_conversation_data", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_conversation_dataset_rest_unset_required_fields(): + transport = transports.ConversationDatasetsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + unset_fields = transport.get_conversation_dataset._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_conversation_dataset_rest_interceptors(null_interceptor): + transport = transports.ConversationDatasetsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationDatasetsRestInterceptor(), + ) + client = ConversationDatasetsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationDatasetsRestInterceptor, "post_get_conversation_dataset" + ) as post, mock.patch.object( + transports.ConversationDatasetsRestInterceptor, "pre_get_conversation_dataset" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_dataset.GetConversationDatasetRequest.pb( + conversation_dataset.GetConversationDatasetRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation_dataset.ConversationDataset.to_json( + conversation_dataset.ConversationDataset() + ) + + request = conversation_dataset.GetConversationDatasetRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation_dataset.ConversationDataset() + + client.get_conversation_dataset( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_conversation_dataset_rest_bad_request( + transport: str = "rest", + request_type=conversation_dataset.GetConversationDatasetRequest, +): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationDatasets/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_conversation_dataset(request) + + +def test_get_conversation_dataset_rest_flattened(): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_dataset.ConversationDataset() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/conversationDatasets/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_dataset.ConversationDataset.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_conversation_dataset(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/conversationDatasets/*}" % client.transport._host, + args[1], + ) + + +def test_get_conversation_dataset_rest_flattened_error(transport: str = "rest"): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_conversation_dataset( + conversation_dataset.GetConversationDatasetRequest(), + name="name_value", + ) + + +def test_get_conversation_dataset_rest_error(): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_dataset.ListConversationDatasetsRequest, + dict, + ], +) +def test_list_conversation_datasets_rest(request_type): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_dataset.ListConversationDatasetsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_dataset.ListConversationDatasetsResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_conversation_datasets(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListConversationDatasetsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_conversation_datasets_rest_required_fields( + request_type=conversation_dataset.ListConversationDatasetsRequest, +): + transport_class = transports.ConversationDatasetsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversation_datasets._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversation_datasets._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation_dataset.ListConversationDatasetsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation_dataset.ListConversationDatasetsResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_conversation_datasets(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_conversation_datasets_rest_unset_required_fields(): + transport = transports.ConversationDatasetsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_conversation_datasets._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_conversation_datasets_rest_interceptors(null_interceptor): + transport = transports.ConversationDatasetsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationDatasetsRestInterceptor(), + ) + client = ConversationDatasetsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationDatasetsRestInterceptor, + "post_list_conversation_datasets", + ) as post, mock.patch.object( + transports.ConversationDatasetsRestInterceptor, "pre_list_conversation_datasets" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_dataset.ListConversationDatasetsRequest.pb( + conversation_dataset.ListConversationDatasetsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + conversation_dataset.ListConversationDatasetsResponse.to_json( + conversation_dataset.ListConversationDatasetsResponse() + ) + ) + + request = conversation_dataset.ListConversationDatasetsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation_dataset.ListConversationDatasetsResponse() + + client.list_conversation_datasets( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_conversation_datasets_rest_bad_request( + transport: str = "rest", + request_type=conversation_dataset.ListConversationDatasetsRequest, +): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_conversation_datasets(request) + + +def test_list_conversation_datasets_rest_flattened(): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_dataset.ListConversationDatasetsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_dataset.ListConversationDatasetsResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_conversation_datasets(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/conversationDatasets" % client.transport._host, + args[1], + ) + + +def test_list_conversation_datasets_rest_flattened_error(transport: str = "rest"): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_conversation_datasets( + conversation_dataset.ListConversationDatasetsRequest(), + parent="parent_value", + ) + + +def test_list_conversation_datasets_rest_pager(transport: str = "rest"): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + conversation_dataset.ListConversationDatasetsResponse( + conversation_datasets=[ + conversation_dataset.ConversationDataset(), + conversation_dataset.ConversationDataset(), + conversation_dataset.ConversationDataset(), + ], + next_page_token="abc", + ), + conversation_dataset.ListConversationDatasetsResponse( + conversation_datasets=[], + next_page_token="def", + ), + conversation_dataset.ListConversationDatasetsResponse( + conversation_datasets=[ + conversation_dataset.ConversationDataset(), + ], + next_page_token="ghi", + ), + conversation_dataset.ListConversationDatasetsResponse( + conversation_datasets=[ + conversation_dataset.ConversationDataset(), + conversation_dataset.ConversationDataset(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + conversation_dataset.ListConversationDatasetsResponse.to_json(x) + for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1"} + + pager = client.list_conversation_datasets(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all( + isinstance(i, conversation_dataset.ConversationDataset) for i in results + ) + + pages = list(client.list_conversation_datasets(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_dataset.DeleteConversationDatasetRequest, + dict, + ], +) +def test_delete_conversation_dataset_rest(request_type): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/conversationDatasets/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_conversation_dataset(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_delete_conversation_dataset_rest_required_fields( + request_type=conversation_dataset.DeleteConversationDatasetRequest, +): + transport_class = transports.ConversationDatasetsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_conversation_dataset._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_conversation_dataset._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_conversation_dataset(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_conversation_dataset_rest_unset_required_fields(): + transport = transports.ConversationDatasetsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_conversation_dataset._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_conversation_dataset_rest_interceptors(null_interceptor): + transport = transports.ConversationDatasetsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationDatasetsRestInterceptor(), + ) + client = ConversationDatasetsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationDatasetsRestInterceptor, + "post_delete_conversation_dataset", + ) as post, mock.patch.object( + transports.ConversationDatasetsRestInterceptor, + "pre_delete_conversation_dataset", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_dataset.DeleteConversationDatasetRequest.pb( + conversation_dataset.DeleteConversationDatasetRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = conversation_dataset.DeleteConversationDatasetRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.delete_conversation_dataset( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_delete_conversation_dataset_rest_bad_request( + transport: str = "rest", + request_type=conversation_dataset.DeleteConversationDatasetRequest, +): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/locations/sample2/conversationDatasets/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_conversation_dataset(request) + + +def test_delete_conversation_dataset_rest_flattened(): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/conversationDatasets/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_conversation_dataset(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/locations/*/conversationDatasets/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_conversation_dataset_rest_flattened_error(transport: str = "rest"): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_conversation_dataset( + conversation_dataset.DeleteConversationDatasetRequest(), + name="name_value", + ) + + +def test_delete_conversation_dataset_rest_error(): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_dataset.ImportConversationDataRequest, + dict, + ], +) +def test_import_conversation_data_rest(request_type): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationDatasets/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.import_conversation_data(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_import_conversation_data_rest_required_fields( + request_type=conversation_dataset.ImportConversationDataRequest, +): + transport_class = transports.ConversationDatasetsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).import_conversation_data._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).import_conversation_data._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.import_conversation_data(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_import_conversation_data_rest_unset_required_fields(): + transport = transports.ConversationDatasetsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.import_conversation_data._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "name", + "inputConfig", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_import_conversation_data_rest_interceptors(null_interceptor): + transport = transports.ConversationDatasetsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationDatasetsRestInterceptor(), + ) + client = ConversationDatasetsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationDatasetsRestInterceptor, "post_import_conversation_data" + ) as post, mock.patch.object( + transports.ConversationDatasetsRestInterceptor, "pre_import_conversation_data" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_dataset.ImportConversationDataRequest.pb( + conversation_dataset.ImportConversationDataRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = conversation_dataset.ImportConversationDataRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.import_conversation_data( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_import_conversation_data_rest_bad_request( + transport: str = "rest", + request_type=conversation_dataset.ImportConversationDataRequest, +): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationDatasets/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.import_conversation_data(request) + + +def test_import_conversation_data_rest_error(): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ConversationDatasetsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ConversationDatasetsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationDatasetsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ConversationDatasetsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationDatasetsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationDatasetsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ConversationDatasetsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationDatasetsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationDatasetsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ConversationDatasetsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationDatasetsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ConversationDatasetsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ConversationDatasetsGrpcTransport, + transports.ConversationDatasetsGrpcAsyncIOTransport, + transports.ConversationDatasetsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = ConversationDatasetsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ConversationDatasetsGrpcTransport, + ) + + +def test_conversation_datasets_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ConversationDatasetsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_conversation_datasets_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.conversation_datasets.transports.ConversationDatasetsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ConversationDatasetsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "create_conversation_dataset", + "get_conversation_dataset", + "list_conversation_datasets", + "delete_conversation_dataset", + "import_conversation_data", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client # Catch all for all remaining methods and properties remainder = [ @@ -2331,6 +3793,7 @@ def test_conversation_datasets_transport_auth_adc(transport_class): [ transports.ConversationDatasetsGrpcTransport, transports.ConversationDatasetsGrpcAsyncIOTransport, + transports.ConversationDatasetsRestTransport, ], ) def test_conversation_datasets_transport_auth_gdch_credentials(transport_class): @@ -2433,11 +3896,40 @@ def test_conversation_datasets_grpc_transport_client_cert_source_for_mtls( ) +def test_conversation_datasets_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.ConversationDatasetsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_conversation_datasets_rest_lro_client(): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversation_datasets_host_no_port(transport_name): @@ -2448,7 +3940,11 @@ def test_conversation_datasets_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2456,6 +3952,7 @@ def test_conversation_datasets_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversation_datasets_host_with_port(transport_name): @@ -2466,7 +3963,45 @@ def test_conversation_datasets_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_conversation_datasets_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ConversationDatasetsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ConversationDatasetsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_conversation_dataset._session + session2 = client2.transport.create_conversation_dataset._session + assert session1 != session2 + session1 = client1.transport.get_conversation_dataset._session + session2 = client2.transport.get_conversation_dataset._session + assert session1 != session2 + session1 = client1.transport.list_conversation_datasets._session + session2 = client2.transport.list_conversation_datasets._session + assert session1 != session2 + session1 = client1.transport.delete_conversation_dataset._session + session2 = client2.transport.delete_conversation_dataset._session + assert session1 != session2 + session1 = client1.transport.import_conversation_data._session + session2 = client2.transport.import_conversation_data._session + assert session1 != session2 def test_conversation_datasets_grpc_transport_channel(): @@ -2797,6 +4332,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ConversationDatasetsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ConversationDatasetsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3518,6 +5339,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3535,6 +5357,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_conversation_models.py b/tests/unit/gapic/dialogflow_v2/test_conversation_models.py index 4ff455006..490e5253f 100644 --- a/tests/unit/gapic/dialogflow_v2/test_conversation_models.py +++ b/tests/unit/gapic/dialogflow_v2/test_conversation_models.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -43,12 +45,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import empty_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.conversation_models import ( ConversationModelsAsyncClient, @@ -112,6 +117,7 @@ def test__get_default_mtls_endpoint(): [ (ConversationModelsClient, "grpc"), (ConversationModelsAsyncClient, "grpc_asyncio"), + (ConversationModelsClient, "rest"), ], ) def test_conversation_models_client_from_service_account_info( @@ -127,7 +133,11 @@ def test_conversation_models_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -135,6 +145,7 @@ def test_conversation_models_client_from_service_account_info( [ (transports.ConversationModelsGrpcTransport, "grpc"), (transports.ConversationModelsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ConversationModelsRestTransport, "rest"), ], ) def test_conversation_models_client_service_account_always_use_jwt( @@ -160,6 +171,7 @@ def test_conversation_models_client_service_account_always_use_jwt( [ (ConversationModelsClient, "grpc"), (ConversationModelsAsyncClient, "grpc_asyncio"), + (ConversationModelsClient, "rest"), ], ) def test_conversation_models_client_from_service_account_file( @@ -182,13 +194,18 @@ def test_conversation_models_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_conversation_models_client_get_transport_class(): transport = ConversationModelsClient.get_transport_class() available_transports = [ transports.ConversationModelsGrpcTransport, + transports.ConversationModelsRestTransport, ] assert transport in available_transports @@ -205,6 +222,7 @@ def test_conversation_models_client_get_transport_class(): transports.ConversationModelsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ConversationModelsClient, transports.ConversationModelsRestTransport, "rest"), ], ) @mock.patch.object( @@ -360,6 +378,18 @@ def test_conversation_models_client_client_options( "grpc_asyncio", "false", ), + ( + ConversationModelsClient, + transports.ConversationModelsRestTransport, + "rest", + "true", + ), + ( + ConversationModelsClient, + transports.ConversationModelsRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -559,6 +589,7 @@ def test_conversation_models_client_get_mtls_endpoint_and_cert_source(client_cla transports.ConversationModelsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ConversationModelsClient, transports.ConversationModelsRestTransport, "rest"), ], ) def test_conversation_models_client_client_options_scopes( @@ -599,6 +630,12 @@ def test_conversation_models_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + ConversationModelsClient, + transports.ConversationModelsRestTransport, + "rest", + None, + ), ], ) def test_conversation_models_client_client_options_credentials_file( @@ -3203,187 +3240,2734 @@ async def test_create_conversation_model_evaluation_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ConversationModelsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation_model.CreateConversationModelRequest, + dict, + ], +) +def test_create_conversation_model_rest(request_type): + client = ConversationModelsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = ConversationModelsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["conversation_model"] = { + "name": "name_value", + "display_name": "display_name_value", + "create_time": {"seconds": 751, "nanos": 543}, + "datasets": [{"dataset": "dataset_value"}], + "state": 1, + "language_code": "language_code_value", + "article_suggestion_model_metadata": {"training_model_type": 2}, + "smart_reply_model_metadata": {"training_model_type": 2}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_conversation_model(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_create_conversation_model_rest_required_fields( + request_type=gcd_conversation_model.CreateConversationModelRequest, +): + transport_class = transports.ConversationModelsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ConversationModelsGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation_model._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation_model._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = ConversationModelsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_conversation_model(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_conversation_model_rest_unset_required_fields(): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - with pytest.raises(ValueError): - client = ConversationModelsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) - # It is an error to provide an api_key and a transport instance. - transport = transports.ConversationModelsGrpcTransport( + unset_fields = transport.create_conversation_model._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("conversationModel",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_conversation_model_rest_interceptors(null_interceptor): + transport = transports.ConversationModelsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationModelsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationModelsClient( - client_options=options, - transport=transport, + client = ConversationModelsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationModelsRestInterceptor, "post_create_conversation_model" + ) as post, mock.patch.object( + transports.ConversationModelsRestInterceptor, "pre_create_conversation_model" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation_model.CreateConversationModelRequest.pb( + gcd_conversation_model.CreateConversationModelRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationModelsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + request = gcd_conversation_model.CreateConversationModelRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() - # It is an error to provide scopes and a transport instance. - transport = transports.ConversationModelsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = ConversationModelsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client.create_conversation_model( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) + pre.assert_called_once() + post.assert_called_once() -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationModelsGrpcTransport( + +def test_create_conversation_model_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation_model.CreateConversationModelRequest, +): + client = ConversationModelsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = ConversationModelsClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["conversation_model"] = { + "name": "name_value", + "display_name": "display_name_value", + "create_time": {"seconds": 751, "nanos": 543}, + "datasets": [{"dataset": "dataset_value"}], + "state": 1, + "language_code": "language_code_value", + "article_suggestion_model_metadata": {"training_model_type": 2}, + "smart_reply_model_metadata": {"training_model_type": 2}, + } + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationModelsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_conversation_model(request) + + +def test_create_conversation_model_rest_flattened(): + client = ConversationModelsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.ConversationModelsGrpcAsyncIOTransport( + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + conversation_model=gcd_conversation_model.ConversationModel( + name="name_value" + ), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_conversation_model(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/conversationModels" % client.transport._host, + args[1], + ) + + +def test_create_conversation_model_rest_flattened_error(transport: str = "rest"): + client = ConversationModelsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_conversation_model( + gcd_conversation_model.CreateConversationModelRequest(), + parent="parent_value", + conversation_model=gcd_conversation_model.ConversationModel( + name="name_value" + ), + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.ConversationModelsGrpcTransport, - transports.ConversationModelsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() +def test_create_conversation_model_rest_error(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + conversation_model.GetConversationModelRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = ConversationModelsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name - - -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. +def test_get_conversation_model_rest(request_type): client = ConversationModelsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.ConversationModelsGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationModels/sample2"} + request = request_type(**request_init) -def test_conversation_models_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ConversationModelsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_model.ConversationModel( + name="name_value", + display_name="display_name_value", + state=conversation_model.ConversationModel.State.CREATING, + language_code="language_code_value", + article_suggestion_model_metadata=conversation_model.ArticleSuggestionModelMetadata( + training_model_type=conversation_model.ConversationModel.ModelType.SMART_REPLY_DUAL_ENCODER_MODEL + ), ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_model.ConversationModel.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_conversation_models_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.conversation_models.transports.ConversationModelsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ConversationModelsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_conversation_model(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "create_conversation_model", - "get_conversation_model", - "list_conversation_models", - "delete_conversation_model", - "deploy_conversation_model", - "undeploy_conversation_model", - "get_conversation_model_evaluation", - "list_conversation_model_evaluations", - "create_conversation_model_evaluation", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + # Establish that the response is the type that we expect. + assert isinstance(response, conversation_model.ConversationModel) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.state == conversation_model.ConversationModel.State.CREATING + assert response.language_code == "language_code_value" + + +def test_get_conversation_model_rest_required_fields( + request_type=conversation_model.GetConversationModelRequest, +): + transport_class = transports.ConversationModelsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation_model._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + # verify required fields with default values are now present + jsonified_request["name"] = "name_value" -def test_conversation_models_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.dialogflow_v2.services.conversation_models.transports.ConversationModelsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation_model._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation_model.ConversationModel() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation_model.ConversationModel.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_conversation_model(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_conversation_model_rest_unset_required_fields(): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_conversation_model._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_conversation_model_rest_interceptors(null_interceptor): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationModelsRestInterceptor(), + ) + client = ConversationModelsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationModelsRestInterceptor, "post_get_conversation_model" + ) as post, mock.patch.object( + transports.ConversationModelsRestInterceptor, "pre_get_conversation_model" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_model.GetConversationModelRequest.pb( + conversation_model.GetConversationModelRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation_model.ConversationModel.to_json( + conversation_model.ConversationModel() + ) + + request = conversation_model.GetConversationModelRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation_model.ConversationModel() + + client.get_conversation_model( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_conversation_model_rest_bad_request( + transport: str = "rest", request_type=conversation_model.GetConversationModelRequest +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationModels/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_conversation_model(request) + + +def test_get_conversation_model_rest_flattened(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_model.ConversationModel() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/conversationModels/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_model.ConversationModel.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_conversation_model(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/conversationModels/*}" % client.transport._host, + args[1], + ) + + +def test_get_conversation_model_rest_flattened_error(transport: str = "rest"): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_conversation_model( + conversation_model.GetConversationModelRequest(), + name="name_value", + ) + + +def test_get_conversation_model_rest_error(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_model.ListConversationModelsRequest, + dict, + ], +) +def test_list_conversation_models_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_model.ListConversationModelsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_model.ListConversationModelsResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_conversation_models(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListConversationModelsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_conversation_models_rest_required_fields( + request_type=conversation_model.ListConversationModelsRequest, +): + transport_class = transports.ConversationModelsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversation_models._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversation_models._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation_model.ListConversationModelsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation_model.ListConversationModelsResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_conversation_models(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_conversation_models_rest_unset_required_fields(): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_conversation_models._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_conversation_models_rest_interceptors(null_interceptor): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationModelsRestInterceptor(), + ) + client = ConversationModelsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationModelsRestInterceptor, "post_list_conversation_models" + ) as post, mock.patch.object( + transports.ConversationModelsRestInterceptor, "pre_list_conversation_models" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_model.ListConversationModelsRequest.pb( + conversation_model.ListConversationModelsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + conversation_model.ListConversationModelsResponse.to_json( + conversation_model.ListConversationModelsResponse() + ) + ) + + request = conversation_model.ListConversationModelsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation_model.ListConversationModelsResponse() + + client.list_conversation_models( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_conversation_models_rest_bad_request( + transport: str = "rest", + request_type=conversation_model.ListConversationModelsRequest, +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_conversation_models(request) + + +def test_list_conversation_models_rest_flattened(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_model.ListConversationModelsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_model.ListConversationModelsResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_conversation_models(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/conversationModels" % client.transport._host, + args[1], + ) + + +def test_list_conversation_models_rest_flattened_error(transport: str = "rest"): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_conversation_models( + conversation_model.ListConversationModelsRequest(), + parent="parent_value", + ) + + +def test_list_conversation_models_rest_pager(transport: str = "rest"): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + conversation_model.ListConversationModelsResponse( + conversation_models=[ + conversation_model.ConversationModel(), + conversation_model.ConversationModel(), + conversation_model.ConversationModel(), + ], + next_page_token="abc", + ), + conversation_model.ListConversationModelsResponse( + conversation_models=[], + next_page_token="def", + ), + conversation_model.ListConversationModelsResponse( + conversation_models=[ + conversation_model.ConversationModel(), + ], + next_page_token="ghi", + ), + conversation_model.ListConversationModelsResponse( + conversation_models=[ + conversation_model.ConversationModel(), + conversation_model.ConversationModel(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + conversation_model.ListConversationModelsResponse.to_json(x) + for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1"} + + pager = client.list_conversation_models(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, conversation_model.ConversationModel) for i in results) + + pages = list(client.list_conversation_models(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_model.DeleteConversationModelRequest, + dict, + ], +) +def test_delete_conversation_model_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationModels/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_conversation_model(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_delete_conversation_model_rest_required_fields( + request_type=conversation_model.DeleteConversationModelRequest, +): + transport_class = transports.ConversationModelsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_conversation_model._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_conversation_model._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_conversation_model(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_conversation_model_rest_unset_required_fields(): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_conversation_model._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_conversation_model_rest_interceptors(null_interceptor): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationModelsRestInterceptor(), + ) + client = ConversationModelsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationModelsRestInterceptor, "post_delete_conversation_model" + ) as post, mock.patch.object( + transports.ConversationModelsRestInterceptor, "pre_delete_conversation_model" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_model.DeleteConversationModelRequest.pb( + conversation_model.DeleteConversationModelRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = conversation_model.DeleteConversationModelRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.delete_conversation_model( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_delete_conversation_model_rest_bad_request( + transport: str = "rest", + request_type=conversation_model.DeleteConversationModelRequest, +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationModels/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_conversation_model(request) + + +def test_delete_conversation_model_rest_flattened(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/conversationModels/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_conversation_model(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/conversationModels/*}" % client.transport._host, + args[1], + ) + + +def test_delete_conversation_model_rest_flattened_error(transport: str = "rest"): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_conversation_model( + conversation_model.DeleteConversationModelRequest(), + name="name_value", + ) + + +def test_delete_conversation_model_rest_error(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_model.DeployConversationModelRequest, + dict, + ], +) +def test_deploy_conversation_model_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationModels/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.deploy_conversation_model(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_deploy_conversation_model_rest_required_fields( + request_type=conversation_model.DeployConversationModelRequest, +): + transport_class = transports.ConversationModelsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).deploy_conversation_model._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).deploy_conversation_model._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.deploy_conversation_model(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_deploy_conversation_model_rest_unset_required_fields(): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.deploy_conversation_model._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_deploy_conversation_model_rest_interceptors(null_interceptor): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationModelsRestInterceptor(), + ) + client = ConversationModelsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationModelsRestInterceptor, "post_deploy_conversation_model" + ) as post, mock.patch.object( + transports.ConversationModelsRestInterceptor, "pre_deploy_conversation_model" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_model.DeployConversationModelRequest.pb( + conversation_model.DeployConversationModelRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = conversation_model.DeployConversationModelRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.deploy_conversation_model( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_deploy_conversation_model_rest_bad_request( + transport: str = "rest", + request_type=conversation_model.DeployConversationModelRequest, +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationModels/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.deploy_conversation_model(request) + + +def test_deploy_conversation_model_rest_error(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_model.UndeployConversationModelRequest, + dict, + ], +) +def test_undeploy_conversation_model_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationModels/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.undeploy_conversation_model(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_undeploy_conversation_model_rest_required_fields( + request_type=conversation_model.UndeployConversationModelRequest, +): + transport_class = transports.ConversationModelsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).undeploy_conversation_model._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).undeploy_conversation_model._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.undeploy_conversation_model(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_undeploy_conversation_model_rest_unset_required_fields(): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.undeploy_conversation_model._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_undeploy_conversation_model_rest_interceptors(null_interceptor): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationModelsRestInterceptor(), + ) + client = ConversationModelsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationModelsRestInterceptor, "post_undeploy_conversation_model" + ) as post, mock.patch.object( + transports.ConversationModelsRestInterceptor, "pre_undeploy_conversation_model" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_model.UndeployConversationModelRequest.pb( + conversation_model.UndeployConversationModelRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = conversation_model.UndeployConversationModelRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.undeploy_conversation_model( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_undeploy_conversation_model_rest_bad_request( + transport: str = "rest", + request_type=conversation_model.UndeployConversationModelRequest, +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationModels/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.undeploy_conversation_model(request) + + +def test_undeploy_conversation_model_rest_error(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_model.GetConversationModelEvaluationRequest, + dict, + ], +) +def test_get_conversation_model_evaluation_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/conversationModels/sample2/evaluations/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_model.ConversationModelEvaluation( + name="name_value", + display_name="display_name_value", + raw_human_eval_template_csv="raw_human_eval_template_csv_value", + smart_reply_metrics=conversation_model.SmartReplyMetrics( + allowlist_coverage=0.19260000000000002 + ), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_model.ConversationModelEvaluation.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_conversation_model_evaluation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, conversation_model.ConversationModelEvaluation) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.raw_human_eval_template_csv == "raw_human_eval_template_csv_value" + + +def test_get_conversation_model_evaluation_rest_required_fields( + request_type=conversation_model.GetConversationModelEvaluationRequest, +): + transport_class = transports.ConversationModelsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation_model_evaluation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation_model_evaluation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation_model.ConversationModelEvaluation() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation_model.ConversationModelEvaluation.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_conversation_model_evaluation(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_conversation_model_evaluation_rest_unset_required_fields(): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = ( + transport.get_conversation_model_evaluation._get_unset_required_fields({}) + ) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_conversation_model_evaluation_rest_interceptors(null_interceptor): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationModelsRestInterceptor(), + ) + client = ConversationModelsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationModelsRestInterceptor, + "post_get_conversation_model_evaluation", + ) as post, mock.patch.object( + transports.ConversationModelsRestInterceptor, + "pre_get_conversation_model_evaluation", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_model.GetConversationModelEvaluationRequest.pb( + conversation_model.GetConversationModelEvaluationRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + conversation_model.ConversationModelEvaluation.to_json( + conversation_model.ConversationModelEvaluation() + ) + ) + + request = conversation_model.GetConversationModelEvaluationRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation_model.ConversationModelEvaluation() + + client.get_conversation_model_evaluation( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_conversation_model_evaluation_rest_bad_request( + transport: str = "rest", + request_type=conversation_model.GetConversationModelEvaluationRequest, +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/conversationModels/sample2/evaluations/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_conversation_model_evaluation(request) + + +def test_get_conversation_model_evaluation_rest_flattened(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_model.ConversationModelEvaluation() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/conversationModels/sample2/evaluations/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_model.ConversationModelEvaluation.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_conversation_model_evaluation(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/conversationModels/*/evaluations/*}" + % client.transport._host, + args[1], + ) + + +def test_get_conversation_model_evaluation_rest_flattened_error( + transport: str = "rest", +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_conversation_model_evaluation( + conversation_model.GetConversationModelEvaluationRequest(), + name="name_value", + ) + + +def test_get_conversation_model_evaluation_rest_error(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_model.ListConversationModelEvaluationsRequest, + dict, + ], +) +def test_list_conversation_model_evaluations_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversationModels/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_model.ListConversationModelEvaluationsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = ( + conversation_model.ListConversationModelEvaluationsResponse.pb(return_value) + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_conversation_model_evaluations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListConversationModelEvaluationsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_conversation_model_evaluations_rest_required_fields( + request_type=conversation_model.ListConversationModelEvaluationsRequest, +): + transport_class = transports.ConversationModelsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversation_model_evaluations._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversation_model_evaluations._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation_model.ListConversationModelEvaluationsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = ( + conversation_model.ListConversationModelEvaluationsResponse.pb( + return_value + ) + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_conversation_model_evaluations(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_conversation_model_evaluations_rest_unset_required_fields(): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = ( + transport.list_conversation_model_evaluations._get_unset_required_fields({}) + ) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_conversation_model_evaluations_rest_interceptors(null_interceptor): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationModelsRestInterceptor(), + ) + client = ConversationModelsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationModelsRestInterceptor, + "post_list_conversation_model_evaluations", + ) as post, mock.patch.object( + transports.ConversationModelsRestInterceptor, + "pre_list_conversation_model_evaluations", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_model.ListConversationModelEvaluationsRequest.pb( + conversation_model.ListConversationModelEvaluationsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + conversation_model.ListConversationModelEvaluationsResponse.to_json( + conversation_model.ListConversationModelEvaluationsResponse() + ) + ) + + request = conversation_model.ListConversationModelEvaluationsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = ( + conversation_model.ListConversationModelEvaluationsResponse() + ) + + client.list_conversation_model_evaluations( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_conversation_model_evaluations_rest_bad_request( + transport: str = "rest", + request_type=conversation_model.ListConversationModelEvaluationsRequest, +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversationModels/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_conversation_model_evaluations(request) + + +def test_list_conversation_model_evaluations_rest_flattened(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_model.ListConversationModelEvaluationsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/conversationModels/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = ( + conversation_model.ListConversationModelEvaluationsResponse.pb(return_value) + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_conversation_model_evaluations(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/conversationModels/*}/evaluations" + % client.transport._host, + args[1], + ) + + +def test_list_conversation_model_evaluations_rest_flattened_error( + transport: str = "rest", +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_conversation_model_evaluations( + conversation_model.ListConversationModelEvaluationsRequest(), + parent="parent_value", + ) + + +def test_list_conversation_model_evaluations_rest_pager(transport: str = "rest"): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + conversation_model.ListConversationModelEvaluationsResponse( + conversation_model_evaluations=[ + conversation_model.ConversationModelEvaluation(), + conversation_model.ConversationModelEvaluation(), + conversation_model.ConversationModelEvaluation(), + ], + next_page_token="abc", + ), + conversation_model.ListConversationModelEvaluationsResponse( + conversation_model_evaluations=[], + next_page_token="def", + ), + conversation_model.ListConversationModelEvaluationsResponse( + conversation_model_evaluations=[ + conversation_model.ConversationModelEvaluation(), + ], + next_page_token="ghi", + ), + conversation_model.ListConversationModelEvaluationsResponse( + conversation_model_evaluations=[ + conversation_model.ConversationModelEvaluation(), + conversation_model.ConversationModelEvaluation(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + conversation_model.ListConversationModelEvaluationsResponse.to_json(x) + for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/conversationModels/sample2"} + + pager = client.list_conversation_model_evaluations(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all( + isinstance(i, conversation_model.ConversationModelEvaluation) + for i in results + ) + + pages = list( + client.list_conversation_model_evaluations(request=sample_request).pages + ) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_model.CreateConversationModelEvaluationRequest, + dict, + ], +) +def test_create_conversation_model_evaluation_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/conversationModels/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_conversation_model_evaluation(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_create_conversation_model_evaluation_rest_required_fields( + request_type=conversation_model.CreateConversationModelEvaluationRequest, +): + transport_class = transports.ConversationModelsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation_model_evaluation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation_model_evaluation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_conversation_model_evaluation(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_conversation_model_evaluation_rest_unset_required_fields(): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = ( + transport.create_conversation_model_evaluation._get_unset_required_fields({}) + ) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "conversationModelEvaluation", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_conversation_model_evaluation_rest_interceptors(null_interceptor): + transport = transports.ConversationModelsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationModelsRestInterceptor(), + ) + client = ConversationModelsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationModelsRestInterceptor, + "post_create_conversation_model_evaluation", + ) as post, mock.patch.object( + transports.ConversationModelsRestInterceptor, + "pre_create_conversation_model_evaluation", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_model.CreateConversationModelEvaluationRequest.pb( + conversation_model.CreateConversationModelEvaluationRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = conversation_model.CreateConversationModelEvaluationRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.create_conversation_model_evaluation( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_conversation_model_evaluation_rest_bad_request( + transport: str = "rest", + request_type=conversation_model.CreateConversationModelEvaluationRequest, +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/locations/sample2/conversationModels/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_conversation_model_evaluation(request) + + +def test_create_conversation_model_evaluation_rest_flattened(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/locations/sample2/conversationModels/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + conversation_model_evaluation=conversation_model.ConversationModelEvaluation( + name="name_value" + ), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_conversation_model_evaluation(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/locations/*/conversationModels/*}/evaluations" + % client.transport._host, + args[1], + ) + + +def test_create_conversation_model_evaluation_rest_flattened_error( + transport: str = "rest", +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_conversation_model_evaluation( + conversation_model.CreateConversationModelEvaluationRequest(), + parent="parent_value", + conversation_model_evaluation=conversation_model.ConversationModelEvaluation( + name="name_value" + ), + ) + + +def test_create_conversation_model_evaluation_rest_error(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ConversationModelsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ConversationModelsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationModelsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ConversationModelsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationModelsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationModelsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ConversationModelsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationModelsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationModelsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ConversationModelsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationModelsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ConversationModelsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ConversationModelsGrpcTransport, + transports.ConversationModelsGrpcAsyncIOTransport, + transports.ConversationModelsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = ConversationModelsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ConversationModelsGrpcTransport, + ) + + +def test_conversation_models_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ConversationModelsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_conversation_models_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.conversation_models.transports.ConversationModelsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ConversationModelsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "create_conversation_model", + "get_conversation_model", + "list_conversation_models", + "delete_conversation_model", + "deploy_conversation_model", + "undeploy_conversation_model", + "get_conversation_model_evaluation", + "list_conversation_model_evaluations", + "create_conversation_model_evaluation", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_conversation_models_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.dialogflow_v2.services.conversation_models.transports.ConversationModelsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) transport = transports.ConversationModelsTransport( credentials_file="credentials.json", @@ -3454,6 +6038,7 @@ def test_conversation_models_transport_auth_adc(transport_class): [ transports.ConversationModelsGrpcTransport, transports.ConversationModelsGrpcAsyncIOTransport, + transports.ConversationModelsRestTransport, ], ) def test_conversation_models_transport_auth_gdch_credentials(transport_class): @@ -3556,11 +6141,40 @@ def test_conversation_models_grpc_transport_client_cert_source_for_mtls( ) +def test_conversation_models_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.ConversationModelsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_conversation_models_rest_lro_client(): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversation_models_host_no_port(transport_name): @@ -3571,7 +6185,11 @@ def test_conversation_models_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3579,6 +6197,7 @@ def test_conversation_models_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversation_models_host_with_port(transport_name): @@ -3589,7 +6208,57 @@ def test_conversation_models_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_conversation_models_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ConversationModelsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ConversationModelsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_conversation_model._session + session2 = client2.transport.create_conversation_model._session + assert session1 != session2 + session1 = client1.transport.get_conversation_model._session + session2 = client2.transport.get_conversation_model._session + assert session1 != session2 + session1 = client1.transport.list_conversation_models._session + session2 = client2.transport.list_conversation_models._session + assert session1 != session2 + session1 = client1.transport.delete_conversation_model._session + session2 = client2.transport.delete_conversation_model._session + assert session1 != session2 + session1 = client1.transport.deploy_conversation_model._session + session2 = client2.transport.deploy_conversation_model._session + assert session1 != session2 + session1 = client1.transport.undeploy_conversation_model._session + session2 = client2.transport.undeploy_conversation_model._session + assert session1 != session2 + session1 = client1.transport.get_conversation_model_evaluation._session + session2 = client2.transport.get_conversation_model_evaluation._session + assert session1 != session2 + session1 = client1.transport.list_conversation_model_evaluations._session + session2 = client2.transport.list_conversation_model_evaluations._session + assert session1 != session2 + session1 = client1.transport.create_conversation_model_evaluation._session + session2 = client2.transport.create_conversation_model_evaluation._session + assert session1 != session2 def test_conversation_models_grpc_transport_channel(): @@ -4002,6 +6671,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ConversationModelsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ConversationModelsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4721,6 +7676,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4738,6 +7694,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_conversation_profiles.py b/tests/unit/gapic/dialogflow_v2/test_conversation_profiles.py index 8a799ebb1..88df1ab6a 100644 --- a/tests/unit/gapic/dialogflow_v2/test_conversation_profiles.py +++ b/tests/unit/gapic/dialogflow_v2/test_conversation_profiles.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -43,12 +45,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.conversation_profiles import ( ConversationProfilesAsyncClient, @@ -114,6 +119,7 @@ def test__get_default_mtls_endpoint(): [ (ConversationProfilesClient, "grpc"), (ConversationProfilesAsyncClient, "grpc_asyncio"), + (ConversationProfilesClient, "rest"), ], ) def test_conversation_profiles_client_from_service_account_info( @@ -129,7 +135,11 @@ def test_conversation_profiles_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -137,6 +147,7 @@ def test_conversation_profiles_client_from_service_account_info( [ (transports.ConversationProfilesGrpcTransport, "grpc"), (transports.ConversationProfilesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ConversationProfilesRestTransport, "rest"), ], ) def test_conversation_profiles_client_service_account_always_use_jwt( @@ -162,6 +173,7 @@ def test_conversation_profiles_client_service_account_always_use_jwt( [ (ConversationProfilesClient, "grpc"), (ConversationProfilesAsyncClient, "grpc_asyncio"), + (ConversationProfilesClient, "rest"), ], ) def test_conversation_profiles_client_from_service_account_file( @@ -184,13 +196,18 @@ def test_conversation_profiles_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_conversation_profiles_client_get_transport_class(): transport = ConversationProfilesClient.get_transport_class() available_transports = [ transports.ConversationProfilesGrpcTransport, + transports.ConversationProfilesRestTransport, ] assert transport in available_transports @@ -211,6 +228,11 @@ def test_conversation_profiles_client_get_transport_class(): transports.ConversationProfilesGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + ConversationProfilesClient, + transports.ConversationProfilesRestTransport, + "rest", + ), ], ) @mock.patch.object( @@ -366,6 +388,18 @@ def test_conversation_profiles_client_client_options( "grpc_asyncio", "false", ), + ( + ConversationProfilesClient, + transports.ConversationProfilesRestTransport, + "rest", + "true", + ), + ( + ConversationProfilesClient, + transports.ConversationProfilesRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -569,6 +603,11 @@ def test_conversation_profiles_client_get_mtls_endpoint_and_cert_source(client_c transports.ConversationProfilesGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + ConversationProfilesClient, + transports.ConversationProfilesRestTransport, + "rest", + ), ], ) def test_conversation_profiles_client_client_options_scopes( @@ -609,6 +648,12 @@ def test_conversation_profiles_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + ConversationProfilesClient, + transports.ConversationProfilesRestTransport, + "rest", + None, + ), ], ) def test_conversation_profiles_client_client_options_credentials_file( @@ -2713,172 +2758,2528 @@ async def test_clear_suggestion_feature_config_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ConversationProfilesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + conversation_profile.ListConversationProfilesRequest, + dict, + ], +) +def test_list_conversation_profiles_rest(request_type): + client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ConversationProfilesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ListConversationProfilesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ConversationProfilesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = ConversationProfilesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_profile.ListConversationProfilesResponse.pb( + return_value ) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide an api_key and a transport instance. - transport = transports.ConversationProfilesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationProfilesClient( - client_options=options, - transport=transport, + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_conversation_profiles(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListConversationProfilesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_conversation_profiles_rest_required_fields( + request_type=conversation_profile.ListConversationProfilesRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationProfilesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversation_profiles._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversation_profiles._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", ) + ) + jsonified_request.update(unset_fields) - # It is an error to provide scopes and a transport instance. - transport = transports.ConversationProfilesGrpcTransport( + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ListConversationProfilesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation_profile.ListConversationProfilesResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_conversation_profiles(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_conversation_profiles_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - with pytest.raises(ValueError): - client = ConversationProfilesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + + unset_fields = transport.list_conversation_profiles._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationProfilesGrpcTransport( +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_conversation_profiles_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), ) client = ConversationProfilesClient(transport=transport) - assert client.transport is transport + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "post_list_conversation_profiles", + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, "pre_list_conversation_profiles" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_profile.ListConversationProfilesRequest.pb( + conversation_profile.ListConversationProfilesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + conversation_profile.ListConversationProfilesResponse.to_json( + conversation_profile.ListConversationProfilesResponse() + ) + ) + request = conversation_profile.ListConversationProfilesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation_profile.ListConversationProfilesResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationProfilesGrpcTransport( + client.list_conversation_profiles( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_conversation_profiles_rest_bad_request( + transport: str = "rest", + request_type=conversation_profile.ListConversationProfilesRequest, +): + client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.ConversationProfilesGrpcAsyncIOTransport( + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_conversation_profiles(request) + + +def test_list_conversation_profiles_rest_flattened(): + client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ListConversationProfilesResponse() -@pytest.mark.parametrize( - "transport_class", - [ - transports.ConversationProfilesGrpcTransport, - transports.ConversationProfilesGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = ConversationProfilesClient.get_transport_class(transport_name)( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_profile.ListConversationProfilesResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_conversation_profiles(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/conversationProfiles" % client.transport._host, + args[1], + ) + + +def test_list_conversation_profiles_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - assert transport.kind == transport_name + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_conversation_profiles( + conversation_profile.ListConversationProfilesRequest(), + parent="parent_value", + ) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. +def test_list_conversation_profiles_rest_pager(transport: str = "rest"): client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.ConversationProfilesGrpcTransport, + transport=transport, ) + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + conversation_profile.ListConversationProfilesResponse( + conversation_profiles=[ + conversation_profile.ConversationProfile(), + conversation_profile.ConversationProfile(), + conversation_profile.ConversationProfile(), + ], + next_page_token="abc", + ), + conversation_profile.ListConversationProfilesResponse( + conversation_profiles=[], + next_page_token="def", + ), + conversation_profile.ListConversationProfilesResponse( + conversation_profiles=[ + conversation_profile.ConversationProfile(), + ], + next_page_token="ghi", + ), + conversation_profile.ListConversationProfilesResponse( + conversation_profiles=[ + conversation_profile.ConversationProfile(), + conversation_profile.ConversationProfile(), + ], + ), + ) + # Two responses for two calls + response = response + response -def test_conversation_profiles_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ConversationProfilesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # Wrap the values into proper Response objs + response = tuple( + conversation_profile.ListConversationProfilesResponse.to_json(x) + for x in response ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + sample_request = {"parent": "projects/sample1"} -def test_conversation_profiles_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.conversation_profiles.transports.ConversationProfilesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ConversationProfilesTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + pager = client.list_conversation_profiles(request=sample_request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_conversation_profiles", - "get_conversation_profile", - "create_conversation_profile", - "update_conversation_profile", - "delete_conversation_profile", - "set_suggestion_feature_config", - "clear_suggestion_feature_config", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + results = list(pager) + assert len(results) == 6 + assert all( + isinstance(i, conversation_profile.ConversationProfile) for i in results + ) - with pytest.raises(NotImplementedError): - transport.close() + pages = list(client.list_conversation_profiles(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] +@pytest.mark.parametrize( + "request_type", + [ + conversation_profile.GetConversationProfileRequest, + dict, + ], +) +def test_get_conversation_profile_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationProfiles/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ConversationProfile( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + time_zone="time_zone_value", + security_settings="security_settings_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_conversation_profile(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, conversation_profile.ConversationProfile) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + assert response.time_zone == "time_zone_value" + assert response.security_settings == "security_settings_value" + + +def test_get_conversation_profile_rest_required_fields( + request_type=conversation_profile.GetConversationProfileRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ConversationProfile() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_conversation_profile(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_conversation_profile_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_conversation_profile._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_conversation_profile_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationProfilesRestInterceptor, "post_get_conversation_profile" + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, "pre_get_conversation_profile" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_profile.GetConversationProfileRequest.pb( + conversation_profile.GetConversationProfileRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation_profile.ConversationProfile.to_json( + conversation_profile.ConversationProfile() + ) + + request = conversation_profile.GetConversationProfileRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation_profile.ConversationProfile() + + client.get_conversation_profile( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_conversation_profile_rest_bad_request( + transport: str = "rest", + request_type=conversation_profile.GetConversationProfileRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationProfiles/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_conversation_profile(request) + + +def test_get_conversation_profile_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ConversationProfile() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/conversationProfiles/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_conversation_profile(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/conversationProfiles/*}" % client.transport._host, + args[1], + ) + + +def test_get_conversation_profile_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_conversation_profile( + conversation_profile.GetConversationProfileRequest(), + name="name_value", + ) + + +def test_get_conversation_profile_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation_profile.CreateConversationProfileRequest, + dict, + ], +) +def test_create_conversation_profile_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["conversation_profile"] = { + "name": "name_value", + "display_name": "display_name_value", + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "automated_agent_config": {"agent": "agent_value"}, + "human_agent_assistant_config": { + "notification_config": {"topic": "topic_value", "message_format": 1}, + "human_agent_suggestion_config": { + "feature_configs": [ + { + "suggestion_feature": {"type_": 1}, + "enable_event_based_suggestion": True, + "suggestion_trigger_settings": { + "no_smalltalk": True, + "only_end_user": True, + }, + "query_config": { + "knowledge_base_query_source": { + "knowledge_bases": [ + "knowledge_bases_value1", + "knowledge_bases_value2", + ] + }, + "document_query_source": { + "documents": ["documents_value1", "documents_value2"] + }, + "dialogflow_query_source": {"agent": "agent_value"}, + "max_results": 1207, + "confidence_threshold": 0.2106, + "context_filter_settings": { + "drop_handoff_messages": True, + "drop_virtual_agent_messages": True, + "drop_ivr_messages": True, + }, + }, + "conversation_model_config": {"model": "model_value"}, + "conversation_process_config": {"recent_sentences_count": 2352}, + } + ], + "group_suggestion_responses": True, + }, + "end_user_suggestion_config": {}, + "message_analysis_config": { + "enable_entity_extraction": True, + "enable_sentiment_analysis": True, + }, + }, + "human_agent_handoff_config": { + "live_person_config": {"account_number": "account_number_value"}, + "salesforce_live_agent_config": { + "organization_id": "organization_id_value", + "deployment_id": "deployment_id_value", + "button_id": "button_id_value", + "endpoint_domain": "endpoint_domain_value", + }, + }, + "notification_config": {}, + "logging_config": {"enable_stackdriver_logging": True}, + "new_message_event_notification_config": {}, + "stt_config": {"speech_model_variant": 1, "model": "model_value"}, + "language_code": "language_code_value", + "time_zone": "time_zone_value", + "security_settings": "security_settings_value", + "tts_config": { + "speaking_rate": 0.1373, + "pitch": 0.536, + "volume_gain_db": 0.1467, + "effects_profile_id": [ + "effects_profile_id_value1", + "effects_profile_id_value2", + ], + "voice": {"name": "name_value", "ssml_gender": 1}, + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + time_zone="time_zone_value", + security_settings="security_settings_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_conversation_profile(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_conversation_profile.ConversationProfile) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + assert response.time_zone == "time_zone_value" + assert response.security_settings == "security_settings_value" + + +def test_create_conversation_profile_rest_required_fields( + request_type=gcd_conversation_profile.CreateConversationProfileRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_conversation_profile.ConversationProfile.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_conversation_profile(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_conversation_profile_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_conversation_profile._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "conversationProfile", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_conversation_profile_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "post_create_conversation_profile", + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "pre_create_conversation_profile", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation_profile.CreateConversationProfileRequest.pb( + gcd_conversation_profile.CreateConversationProfileRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + gcd_conversation_profile.ConversationProfile.to_json( + gcd_conversation_profile.ConversationProfile() + ) + ) + + request = gcd_conversation_profile.CreateConversationProfileRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_conversation_profile.ConversationProfile() + + client.create_conversation_profile( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_conversation_profile_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation_profile.CreateConversationProfileRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["conversation_profile"] = { + "name": "name_value", + "display_name": "display_name_value", + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "automated_agent_config": {"agent": "agent_value"}, + "human_agent_assistant_config": { + "notification_config": {"topic": "topic_value", "message_format": 1}, + "human_agent_suggestion_config": { + "feature_configs": [ + { + "suggestion_feature": {"type_": 1}, + "enable_event_based_suggestion": True, + "suggestion_trigger_settings": { + "no_smalltalk": True, + "only_end_user": True, + }, + "query_config": { + "knowledge_base_query_source": { + "knowledge_bases": [ + "knowledge_bases_value1", + "knowledge_bases_value2", + ] + }, + "document_query_source": { + "documents": ["documents_value1", "documents_value2"] + }, + "dialogflow_query_source": {"agent": "agent_value"}, + "max_results": 1207, + "confidence_threshold": 0.2106, + "context_filter_settings": { + "drop_handoff_messages": True, + "drop_virtual_agent_messages": True, + "drop_ivr_messages": True, + }, + }, + "conversation_model_config": {"model": "model_value"}, + "conversation_process_config": {"recent_sentences_count": 2352}, + } + ], + "group_suggestion_responses": True, + }, + "end_user_suggestion_config": {}, + "message_analysis_config": { + "enable_entity_extraction": True, + "enable_sentiment_analysis": True, + }, + }, + "human_agent_handoff_config": { + "live_person_config": {"account_number": "account_number_value"}, + "salesforce_live_agent_config": { + "organization_id": "organization_id_value", + "deployment_id": "deployment_id_value", + "button_id": "button_id_value", + "endpoint_domain": "endpoint_domain_value", + }, + }, + "notification_config": {}, + "logging_config": {"enable_stackdriver_logging": True}, + "new_message_event_notification_config": {}, + "stt_config": {"speech_model_variant": 1, "model": "model_value"}, + "language_code": "language_code_value", + "time_zone": "time_zone_value", + "security_settings": "security_settings_value", + "tts_config": { + "speaking_rate": 0.1373, + "pitch": 0.536, + "volume_gain_db": 0.1467, + "effects_profile_id": [ + "effects_profile_id_value1", + "effects_profile_id_value2", + ], + "voice": {"name": "name_value", "ssml_gender": 1}, + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_conversation_profile(request) + + +def test_create_conversation_profile_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + conversation_profile=gcd_conversation_profile.ConversationProfile( + name="name_value" + ), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_conversation_profile(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/conversationProfiles" % client.transport._host, + args[1], + ) + + +def test_create_conversation_profile_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_conversation_profile( + gcd_conversation_profile.CreateConversationProfileRequest(), + parent="parent_value", + conversation_profile=gcd_conversation_profile.ConversationProfile( + name="name_value" + ), + ) + + +def test_create_conversation_profile_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation_profile.UpdateConversationProfileRequest, + dict, + ], +) +def test_update_conversation_profile_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": { + "name": "projects/sample1/conversationProfiles/sample2" + } + } + request_init["conversation_profile"] = { + "name": "projects/sample1/conversationProfiles/sample2", + "display_name": "display_name_value", + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "automated_agent_config": {"agent": "agent_value"}, + "human_agent_assistant_config": { + "notification_config": {"topic": "topic_value", "message_format": 1}, + "human_agent_suggestion_config": { + "feature_configs": [ + { + "suggestion_feature": {"type_": 1}, + "enable_event_based_suggestion": True, + "suggestion_trigger_settings": { + "no_smalltalk": True, + "only_end_user": True, + }, + "query_config": { + "knowledge_base_query_source": { + "knowledge_bases": [ + "knowledge_bases_value1", + "knowledge_bases_value2", + ] + }, + "document_query_source": { + "documents": ["documents_value1", "documents_value2"] + }, + "dialogflow_query_source": {"agent": "agent_value"}, + "max_results": 1207, + "confidence_threshold": 0.2106, + "context_filter_settings": { + "drop_handoff_messages": True, + "drop_virtual_agent_messages": True, + "drop_ivr_messages": True, + }, + }, + "conversation_model_config": {"model": "model_value"}, + "conversation_process_config": {"recent_sentences_count": 2352}, + } + ], + "group_suggestion_responses": True, + }, + "end_user_suggestion_config": {}, + "message_analysis_config": { + "enable_entity_extraction": True, + "enable_sentiment_analysis": True, + }, + }, + "human_agent_handoff_config": { + "live_person_config": {"account_number": "account_number_value"}, + "salesforce_live_agent_config": { + "organization_id": "organization_id_value", + "deployment_id": "deployment_id_value", + "button_id": "button_id_value", + "endpoint_domain": "endpoint_domain_value", + }, + }, + "notification_config": {}, + "logging_config": {"enable_stackdriver_logging": True}, + "new_message_event_notification_config": {}, + "stt_config": {"speech_model_variant": 1, "model": "model_value"}, + "language_code": "language_code_value", + "time_zone": "time_zone_value", + "security_settings": "security_settings_value", + "tts_config": { + "speaking_rate": 0.1373, + "pitch": 0.536, + "volume_gain_db": 0.1467, + "effects_profile_id": [ + "effects_profile_id_value1", + "effects_profile_id_value2", + ], + "voice": {"name": "name_value", "ssml_gender": 1}, + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + time_zone="time_zone_value", + security_settings="security_settings_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_conversation_profile(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_conversation_profile.ConversationProfile) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + assert response.time_zone == "time_zone_value" + assert response.security_settings == "security_settings_value" + + +def test_update_conversation_profile_rest_required_fields( + request_type=gcd_conversation_profile.UpdateConversationProfileRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_conversation_profile._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_conversation_profile.ConversationProfile.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_conversation_profile(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_conversation_profile_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_conversation_profile._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "conversationProfile", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_conversation_profile_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "post_update_conversation_profile", + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "pre_update_conversation_profile", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation_profile.UpdateConversationProfileRequest.pb( + gcd_conversation_profile.UpdateConversationProfileRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + gcd_conversation_profile.ConversationProfile.to_json( + gcd_conversation_profile.ConversationProfile() + ) + ) + + request = gcd_conversation_profile.UpdateConversationProfileRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_conversation_profile.ConversationProfile() + + client.update_conversation_profile( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_conversation_profile_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation_profile.UpdateConversationProfileRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": { + "name": "projects/sample1/conversationProfiles/sample2" + } + } + request_init["conversation_profile"] = { + "name": "projects/sample1/conversationProfiles/sample2", + "display_name": "display_name_value", + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "automated_agent_config": {"agent": "agent_value"}, + "human_agent_assistant_config": { + "notification_config": {"topic": "topic_value", "message_format": 1}, + "human_agent_suggestion_config": { + "feature_configs": [ + { + "suggestion_feature": {"type_": 1}, + "enable_event_based_suggestion": True, + "suggestion_trigger_settings": { + "no_smalltalk": True, + "only_end_user": True, + }, + "query_config": { + "knowledge_base_query_source": { + "knowledge_bases": [ + "knowledge_bases_value1", + "knowledge_bases_value2", + ] + }, + "document_query_source": { + "documents": ["documents_value1", "documents_value2"] + }, + "dialogflow_query_source": {"agent": "agent_value"}, + "max_results": 1207, + "confidence_threshold": 0.2106, + "context_filter_settings": { + "drop_handoff_messages": True, + "drop_virtual_agent_messages": True, + "drop_ivr_messages": True, + }, + }, + "conversation_model_config": {"model": "model_value"}, + "conversation_process_config": {"recent_sentences_count": 2352}, + } + ], + "group_suggestion_responses": True, + }, + "end_user_suggestion_config": {}, + "message_analysis_config": { + "enable_entity_extraction": True, + "enable_sentiment_analysis": True, + }, + }, + "human_agent_handoff_config": { + "live_person_config": {"account_number": "account_number_value"}, + "salesforce_live_agent_config": { + "organization_id": "organization_id_value", + "deployment_id": "deployment_id_value", + "button_id": "button_id_value", + "endpoint_domain": "endpoint_domain_value", + }, + }, + "notification_config": {}, + "logging_config": {"enable_stackdriver_logging": True}, + "new_message_event_notification_config": {}, + "stt_config": {"speech_model_variant": 1, "model": "model_value"}, + "language_code": "language_code_value", + "time_zone": "time_zone_value", + "security_settings": "security_settings_value", + "tts_config": { + "speaking_rate": 0.1373, + "pitch": 0.536, + "volume_gain_db": 0.1467, + "effects_profile_id": [ + "effects_profile_id_value1", + "effects_profile_id_value2", + ], + "voice": {"name": "name_value", "ssml_gender": 1}, + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_conversation_profile(request) + + +def test_update_conversation_profile_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile() + + # get arguments that satisfy an http rule for this method + sample_request = { + "conversation_profile": { + "name": "projects/sample1/conversationProfiles/sample2" + } + } + + # get truthy value for each flattened field + mock_args = dict( + conversation_profile=gcd_conversation_profile.ConversationProfile( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_conversation_profile(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{conversation_profile.name=projects/*/conversationProfiles/*}" + % client.transport._host, + args[1], + ) + + +def test_update_conversation_profile_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_conversation_profile( + gcd_conversation_profile.UpdateConversationProfileRequest(), + conversation_profile=gcd_conversation_profile.ConversationProfile( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_conversation_profile_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_profile.DeleteConversationProfileRequest, + dict, + ], +) +def test_delete_conversation_profile_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationProfiles/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_conversation_profile(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_conversation_profile_rest_required_fields( + request_type=conversation_profile.DeleteConversationProfileRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_conversation_profile(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_conversation_profile_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_conversation_profile._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_conversation_profile_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "pre_delete_conversation_profile", + ) as pre: + pre.assert_not_called() + pb_message = conversation_profile.DeleteConversationProfileRequest.pb( + conversation_profile.DeleteConversationProfileRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = conversation_profile.DeleteConversationProfileRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_conversation_profile( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_conversation_profile_rest_bad_request( + transport: str = "rest", + request_type=conversation_profile.DeleteConversationProfileRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationProfiles/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_conversation_profile(request) + + +def test_delete_conversation_profile_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/conversationProfiles/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_conversation_profile(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/conversationProfiles/*}" % client.transport._host, + args[1], + ) + + +def test_delete_conversation_profile_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_conversation_profile( + conversation_profile.DeleteConversationProfileRequest(), + name="name_value", + ) + + +def test_delete_conversation_profile_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation_profile.SetSuggestionFeatureConfigRequest, + dict, + ], +) +def test_set_suggestion_feature_config_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.set_suggestion_feature_config(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_set_suggestion_feature_config_rest_required_fields( + request_type=gcd_conversation_profile.SetSuggestionFeatureConfigRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["conversation_profile"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).set_suggestion_feature_config._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["conversationProfile"] = "conversation_profile_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).set_suggestion_feature_config._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "conversationProfile" in jsonified_request + assert jsonified_request["conversationProfile"] == "conversation_profile_value" + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.set_suggestion_feature_config(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_set_suggestion_feature_config_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.set_suggestion_feature_config._get_unset_required_fields( + {} + ) + assert set(unset_fields) == ( + set(()) + & set( + ( + "conversationProfile", + "participantRole", + "suggestionFeatureConfig", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_set_suggestion_feature_config_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "post_set_suggestion_feature_config", + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "pre_set_suggestion_feature_config", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation_profile.SetSuggestionFeatureConfigRequest.pb( + gcd_conversation_profile.SetSuggestionFeatureConfigRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = gcd_conversation_profile.SetSuggestionFeatureConfigRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.set_suggestion_feature_config( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_set_suggestion_feature_config_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation_profile.SetSuggestionFeatureConfigRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.set_suggestion_feature_config(request) + + +def test_set_suggestion_feature_config_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + + # get truthy value for each flattened field + mock_args = dict( + conversation_profile="conversation_profile_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.set_suggestion_feature_config(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{conversation_profile=projects/*/conversationProfiles/*}:setSuggestionFeatureConfig" + % client.transport._host, + args[1], + ) + + +def test_set_suggestion_feature_config_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.set_suggestion_feature_config( + gcd_conversation_profile.SetSuggestionFeatureConfigRequest(), + conversation_profile="conversation_profile_value", + ) + + +def test_set_suggestion_feature_config_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, + dict, + ], +) +def test_clear_suggestion_feature_config_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.clear_suggestion_feature_config(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_clear_suggestion_feature_config_rest_required_fields( + request_type=gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["conversation_profile"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).clear_suggestion_feature_config._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["conversationProfile"] = "conversation_profile_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).clear_suggestion_feature_config._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "conversationProfile" in jsonified_request + assert jsonified_request["conversationProfile"] == "conversation_profile_value" + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.clear_suggestion_feature_config(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_clear_suggestion_feature_config_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.clear_suggestion_feature_config._get_unset_required_fields( + {} + ) + assert set(unset_fields) == ( + set(()) + & set( + ( + "conversationProfile", + "participantRole", + "suggestionFeatureType", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_clear_suggestion_feature_config_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "post_clear_suggestion_feature_config", + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "pre_clear_suggestion_feature_config", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation_profile.ClearSuggestionFeatureConfigRequest.pb( + gcd_conversation_profile.ClearSuggestionFeatureConfigRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = gcd_conversation_profile.ClearSuggestionFeatureConfigRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.clear_suggestion_feature_config( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_clear_suggestion_feature_config_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.clear_suggestion_feature_config(request) + + +def test_clear_suggestion_feature_config_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + + # get truthy value for each flattened field + mock_args = dict( + conversation_profile="conversation_profile_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.clear_suggestion_feature_config(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{conversation_profile=projects/*/conversationProfiles/*}:clearSuggestionFeatureConfig" + % client.transport._host, + args[1], + ) + + +def test_clear_suggestion_feature_config_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.clear_suggestion_feature_config( + gcd_conversation_profile.ClearSuggestionFeatureConfigRequest(), + conversation_profile="conversation_profile_value", + ) + + +def test_clear_suggestion_feature_config_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationProfilesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationProfilesClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationProfilesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationProfilesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ConversationProfilesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ConversationProfilesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ConversationProfilesGrpcTransport, + transports.ConversationProfilesGrpcAsyncIOTransport, + transports.ConversationProfilesRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = ConversationProfilesClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ConversationProfilesGrpcTransport, + ) + + +def test_conversation_profiles_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ConversationProfilesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_conversation_profiles_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.conversation_profiles.transports.ConversationProfilesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ConversationProfilesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_conversation_profiles", + "get_conversation_profile", + "create_conversation_profile", + "update_conversation_profile", + "delete_conversation_profile", + "set_suggestion_feature_config", + "clear_suggestion_feature_config", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] for r in remainder: with pytest.raises(NotImplementedError): getattr(transport, r)() @@ -2962,6 +5363,7 @@ def test_conversation_profiles_transport_auth_adc(transport_class): [ transports.ConversationProfilesGrpcTransport, transports.ConversationProfilesGrpcAsyncIOTransport, + transports.ConversationProfilesRestTransport, ], ) def test_conversation_profiles_transport_auth_gdch_credentials(transport_class): @@ -3064,11 +5466,40 @@ def test_conversation_profiles_grpc_transport_client_cert_source_for_mtls( ) +def test_conversation_profiles_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.ConversationProfilesRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_conversation_profiles_rest_lro_client(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversation_profiles_host_no_port(transport_name): @@ -3079,7 +5510,11 @@ def test_conversation_profiles_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3087,6 +5522,7 @@ def test_conversation_profiles_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversation_profiles_host_with_port(transport_name): @@ -3097,7 +5533,51 @@ def test_conversation_profiles_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_conversation_profiles_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ConversationProfilesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ConversationProfilesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_conversation_profiles._session + session2 = client2.transport.list_conversation_profiles._session + assert session1 != session2 + session1 = client1.transport.get_conversation_profile._session + session2 = client2.transport.get_conversation_profile._session + assert session1 != session2 + session1 = client1.transport.create_conversation_profile._session + session2 = client2.transport.create_conversation_profile._session + assert session1 != session2 + session1 = client1.transport.update_conversation_profile._session + session2 = client2.transport.update_conversation_profile._session + assert session1 != session2 + session1 = client1.transport.delete_conversation_profile._session + session2 = client2.transport.delete_conversation_profile._session + assert session1 != session2 + session1 = client1.transport.set_suggestion_feature_config._session + session2 = client2.transport.set_suggestion_feature_config._session + assert session1 != session2 + session1 = client1.transport.clear_suggestion_feature_config._session + session2 = client2.transport.clear_suggestion_feature_config._session + assert session1 != session2 def test_conversation_profiles_grpc_transport_channel(): @@ -3550,6 +6030,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4271,6 +7037,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4288,6 +7055,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_conversations.py b/tests/unit/gapic/dialogflow_v2/test_conversations.py index 057a95604..eb75ae541 100644 --- a/tests/unit/gapic/dialogflow_v2/test_conversations.py +++ b/tests/unit/gapic/dialogflow_v2/test_conversations.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -33,12 +35,15 @@ from google.cloud.location import locations_pb2 from google.longrunning import operations_pb2 from google.oauth2 import service_account +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.conversations import ( ConversationsAsyncClient, @@ -100,6 +105,7 @@ def test__get_default_mtls_endpoint(): [ (ConversationsClient, "grpc"), (ConversationsAsyncClient, "grpc_asyncio"), + (ConversationsClient, "rest"), ], ) def test_conversations_client_from_service_account_info(client_class, transport_name): @@ -113,7 +119,11 @@ def test_conversations_client_from_service_account_info(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -121,6 +131,7 @@ def test_conversations_client_from_service_account_info(client_class, transport_ [ (transports.ConversationsGrpcTransport, "grpc"), (transports.ConversationsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ConversationsRestTransport, "rest"), ], ) def test_conversations_client_service_account_always_use_jwt( @@ -146,6 +157,7 @@ def test_conversations_client_service_account_always_use_jwt( [ (ConversationsClient, "grpc"), (ConversationsAsyncClient, "grpc_asyncio"), + (ConversationsClient, "rest"), ], ) def test_conversations_client_from_service_account_file(client_class, transport_name): @@ -166,13 +178,18 @@ def test_conversations_client_from_service_account_file(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_conversations_client_get_transport_class(): transport = ConversationsClient.get_transport_class() available_transports = [ transports.ConversationsGrpcTransport, + transports.ConversationsRestTransport, ] assert transport in available_transports @@ -189,6 +206,7 @@ def test_conversations_client_get_transport_class(): transports.ConversationsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ConversationsClient, transports.ConversationsRestTransport, "rest"), ], ) @mock.patch.object( @@ -334,6 +352,8 @@ def test_conversations_client_client_options( "grpc_asyncio", "false", ), + (ConversationsClient, transports.ConversationsRestTransport, "rest", "true"), + (ConversationsClient, transports.ConversationsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -533,6 +553,7 @@ def test_conversations_client_get_mtls_endpoint_and_cert_source(client_class): transports.ConversationsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ConversationsClient, transports.ConversationsRestTransport, "rest"), ], ) def test_conversations_client_client_options_scopes( @@ -573,6 +594,7 @@ def test_conversations_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (ConversationsClient, transports.ConversationsRestTransport, "rest", None), ], ) def test_conversations_client_client_options_credentials_file( @@ -2605,161 +2627,1988 @@ async def test_suggest_conversation_summary_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ConversationsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation.CreateConversationRequest, + dict, + ], +) +def test_create_conversation_rest(request_type): + client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = ConversationsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["conversation"] = { + "name": "name_value", + "lifecycle_state": 1, + "conversation_profile": "conversation_profile_value", + "phone_number": {"phone_number": "phone_number_value"}, + "start_time": {"seconds": 751, "nanos": 543}, + "end_time": {}, + "conversation_stage": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.Conversation( + name="name_value", + lifecycle_state=gcd_conversation.Conversation.LifecycleState.IN_PROGRESS, + conversation_profile="conversation_profile_value", + conversation_stage=gcd_conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE, ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ConversationsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_conversation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_conversation.Conversation) + assert response.name == "name_value" + assert ( + response.lifecycle_state + == gcd_conversation.Conversation.LifecycleState.IN_PROGRESS ) - with pytest.raises(ValueError): - client = ConversationsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + assert response.conversation_profile == "conversation_profile_value" + assert ( + response.conversation_stage + == gcd_conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE + ) + + +def test_create_conversation_rest_required_fields( + request_type=gcd_conversation.CreateConversationRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.ConversationsGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("conversation_id",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.Conversation() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_conversation(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_conversation_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationsClient( - client_options=options, - transport=transport, - ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + unset_fields = transport.create_conversation._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("conversationId",)) + & set( + ( + "parent", + "conversation", + ) ) + ) - # It is an error to provide scopes and a transport instance. - transport = transports.ConversationsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_conversation_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), ) - with pytest.raises(ValueError): - client = ConversationsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_create_conversation" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_create_conversation" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation.CreateConversationRequest.pb( + gcd_conversation.CreateConversationRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_conversation.Conversation.to_json( + gcd_conversation.Conversation() ) + request = gcd_conversation.CreateConversationRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_conversation.Conversation() -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationsGrpcTransport( + client.create_conversation( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_conversation_rest_bad_request( + transport: str = "rest", request_type=gcd_conversation.CreateConversationRequest +): + client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = ConversationsClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["conversation"] = { + "name": "name_value", + "lifecycle_state": 1, + "conversation_profile": "conversation_profile_value", + "phone_number": {"phone_number": "phone_number_value"}, + "start_time": {"seconds": 751, "nanos": 543}, + "end_time": {}, + "conversation_stage": 1, + } + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_conversation(request) + + +def test_create_conversation_rest_flattened(): + client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.ConversationsGrpcAsyncIOTransport( + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.Conversation() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + conversation=gcd_conversation.Conversation(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_conversation(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/conversations" % client.transport._host, args[1] + ) + + +def test_create_conversation_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_conversation( + gcd_conversation.CreateConversationRequest(), + parent="parent_value", + conversation=gcd_conversation.Conversation(name="name_value"), + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.ConversationsGrpcTransport, - transports.ConversationsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() +def test_create_conversation_rest_error(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + conversation.ListConversationsRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = ConversationsClient.get_transport_class(transport_name)( +def test_list_conversations_rest(request_type): + client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.ListConversationsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.ListConversationsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_conversations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListConversationsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_conversations_rest_required_fields( + request_type=conversation.ListConversationsRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversations._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversations._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "filter", + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation.ListConversationsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation.ListConversationsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_conversations(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_conversations_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.ConversationsGrpcTransport, + + unset_fields = transport.list_conversations._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) ) -def test_conversations_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ConversationsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_conversations_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), + ) + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_list_conversations" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_list_conversations" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation.ListConversationsRequest.pb( + conversation.ListConversationsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation.ListConversationsResponse.to_json( + conversation.ListConversationsResponse() ) + request = conversation.ListConversationsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation.ListConversationsResponse() -def test_conversations_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.conversations.transports.ConversationsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ConversationsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_conversations( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "create_conversation", - "list_conversations", - "get_conversation", - "complete_conversation", - "list_messages", - "suggest_conversation_summary", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + pre.assert_called_once() + post.assert_called_once() + + +def test_list_conversations_rest_bad_request( + transport: str = "rest", request_type=conversation.ListConversationsRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_conversations(request) + + +def test_list_conversations_rest_flattened(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.ListConversationsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.ListConversationsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_conversations(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/conversations" % client.transport._host, args[1] + ) + + +def test_list_conversations_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_conversations( + conversation.ListConversationsRequest(), + parent="parent_value", + ) + + +def test_list_conversations_rest_pager(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + conversation.ListConversationsResponse( + conversations=[ + conversation.Conversation(), + conversation.Conversation(), + conversation.Conversation(), + ], + next_page_token="abc", + ), + conversation.ListConversationsResponse( + conversations=[], + next_page_token="def", + ), + conversation.ListConversationsResponse( + conversations=[ + conversation.Conversation(), + ], + next_page_token="ghi", + ), + conversation.ListConversationsResponse( + conversations=[ + conversation.Conversation(), + conversation.Conversation(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + conversation.ListConversationsResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1"} + + pager = client.list_conversations(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, conversation.Conversation) for i in results) + + pages = list(client.list_conversations(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + conversation.GetConversationRequest, + dict, + ], +) +def test_get_conversation_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation( + name="name_value", + lifecycle_state=conversation.Conversation.LifecycleState.IN_PROGRESS, + conversation_profile="conversation_profile_value", + conversation_stage=conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_conversation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, conversation.Conversation) + assert response.name == "name_value" + assert ( + response.lifecycle_state == conversation.Conversation.LifecycleState.IN_PROGRESS + ) + assert response.conversation_profile == "conversation_profile_value" + assert ( + response.conversation_stage + == conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE + ) + + +def test_get_conversation_rest_required_fields( + request_type=conversation.GetConversationRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_conversation(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_conversation_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_conversation._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_conversation_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), + ) + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_get_conversation" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_get_conversation" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation.GetConversationRequest.pb( + conversation.GetConversationRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation.Conversation.to_json( + conversation.Conversation() + ) + + request = conversation.GetConversationRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation.Conversation() + + client.get_conversation( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_conversation_rest_bad_request( + transport: str = "rest", request_type=conversation.GetConversationRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_conversation(request) + + +def test_get_conversation_rest_flattened(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_conversation(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/conversations/*}" % client.transport._host, args[1] + ) + + +def test_get_conversation_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_conversation( + conversation.GetConversationRequest(), + name="name_value", + ) + + +def test_get_conversation_rest_error(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation.CompleteConversationRequest, + dict, + ], +) +def test_complete_conversation_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation( + name="name_value", + lifecycle_state=conversation.Conversation.LifecycleState.IN_PROGRESS, + conversation_profile="conversation_profile_value", + conversation_stage=conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.complete_conversation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, conversation.Conversation) + assert response.name == "name_value" + assert ( + response.lifecycle_state == conversation.Conversation.LifecycleState.IN_PROGRESS + ) + assert response.conversation_profile == "conversation_profile_value" + assert ( + response.conversation_stage + == conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE + ) + + +def test_complete_conversation_rest_required_fields( + request_type=conversation.CompleteConversationRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).complete_conversation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).complete_conversation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.complete_conversation(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_complete_conversation_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.complete_conversation._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_complete_conversation_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), + ) + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_complete_conversation" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_complete_conversation" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation.CompleteConversationRequest.pb( + conversation.CompleteConversationRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation.Conversation.to_json( + conversation.Conversation() + ) + + request = conversation.CompleteConversationRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation.Conversation() + + client.complete_conversation( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_complete_conversation_rest_bad_request( + transport: str = "rest", request_type=conversation.CompleteConversationRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.complete_conversation(request) + + +def test_complete_conversation_rest_flattened(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.complete_conversation(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/conversations/*}:complete" % client.transport._host, + args[1], + ) + + +def test_complete_conversation_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.complete_conversation( + conversation.CompleteConversationRequest(), + name="name_value", + ) + + +def test_complete_conversation_rest_error(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation.ListMessagesRequest, + dict, + ], +) +def test_list_messages_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.ListMessagesResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.ListMessagesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_messages(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListMessagesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_messages_rest_required_fields( + request_type=conversation.ListMessagesRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_messages._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_messages._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "filter", + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation.ListMessagesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation.ListMessagesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_messages(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_messages_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_messages._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_messages_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), + ) + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_list_messages" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_list_messages" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation.ListMessagesRequest.pb( + conversation.ListMessagesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation.ListMessagesResponse.to_json( + conversation.ListMessagesResponse() + ) + + request = conversation.ListMessagesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation.ListMessagesResponse() + + client.list_messages( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_messages_rest_bad_request( + transport: str = "rest", request_type=conversation.ListMessagesRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_messages(request) + + +def test_list_messages_rest_flattened(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.ListMessagesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.ListMessagesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_messages(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/conversations/*}/messages" + % client.transport._host, + args[1], + ) + + +def test_list_messages_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_messages( + conversation.ListMessagesRequest(), + parent="parent_value", + ) + + +def test_list_messages_rest_pager(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + conversation.ListMessagesResponse( + messages=[ + participant.Message(), + participant.Message(), + participant.Message(), + ], + next_page_token="abc", + ), + conversation.ListMessagesResponse( + messages=[], + next_page_token="def", + ), + conversation.ListMessagesResponse( + messages=[ + participant.Message(), + ], + next_page_token="ghi", + ), + conversation.ListMessagesResponse( + messages=[ + participant.Message(), + participant.Message(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(conversation.ListMessagesResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/conversations/sample2"} + + pager = client.list_messages(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, participant.Message) for i in results) + + pages = list(client.list_messages(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation.SuggestConversationSummaryRequest, + dict, + ], +) +def test_suggest_conversation_summary_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"conversation": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.SuggestConversationSummaryResponse( + latest_message="latest_message_value", + context_size=1311, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation.SuggestConversationSummaryResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.suggest_conversation_summary(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_conversation.SuggestConversationSummaryResponse) + assert response.latest_message == "latest_message_value" + assert response.context_size == 1311 + + +def test_suggest_conversation_summary_rest_required_fields( + request_type=gcd_conversation.SuggestConversationSummaryRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["conversation"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_conversation_summary._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["conversation"] = "conversation_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_conversation_summary._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "conversation" in jsonified_request + assert jsonified_request["conversation"] == "conversation_value" + + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.SuggestConversationSummaryResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_conversation.SuggestConversationSummaryResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.suggest_conversation_summary(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_suggest_conversation_summary_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.suggest_conversation_summary._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("conversation",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_suggest_conversation_summary_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), + ) + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_suggest_conversation_summary" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_suggest_conversation_summary" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation.SuggestConversationSummaryRequest.pb( + gcd_conversation.SuggestConversationSummaryRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + gcd_conversation.SuggestConversationSummaryResponse.to_json( + gcd_conversation.SuggestConversationSummaryResponse() + ) + ) + + request = gcd_conversation.SuggestConversationSummaryRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_conversation.SuggestConversationSummaryResponse() + + client.suggest_conversation_summary( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_suggest_conversation_summary_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation.SuggestConversationSummaryRequest, +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"conversation": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.suggest_conversation_summary(request) + + +def test_suggest_conversation_summary_rest_flattened(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.SuggestConversationSummaryResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"conversation": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + conversation="conversation_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation.SuggestConversationSummaryResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.suggest_conversation_summary(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{conversation=projects/*/conversations/*}/suggestions:suggestConversationSummary" + % client.transport._host, + args[1], + ) + + +def test_suggest_conversation_summary_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.suggest_conversation_summary( + gcd_conversation.SuggestConversationSummaryRequest(), + conversation="conversation_value", + ) + + +def test_suggest_conversation_summary_rest_error(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ConversationsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ConversationsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ConversationsGrpcTransport, + transports.ConversationsGrpcAsyncIOTransport, + transports.ConversationsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = ConversationsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ConversationsGrpcTransport, + ) + + +def test_conversations_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ConversationsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_conversations_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.conversations.transports.ConversationsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ConversationsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "create_conversation", + "list_conversations", + "get_conversation", + "complete_conversation", + "list_messages", + "suggest_conversation_summary", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() # Catch all for all remaining methods and properties remainder = [ @@ -2848,6 +4697,7 @@ def test_conversations_transport_auth_adc(transport_class): [ transports.ConversationsGrpcTransport, transports.ConversationsGrpcAsyncIOTransport, + transports.ConversationsRestTransport, ], ) def test_conversations_transport_auth_gdch_credentials(transport_class): @@ -2948,11 +4798,23 @@ def test_conversations_grpc_transport_client_cert_source_for_mtls(transport_clas ) +def test_conversations_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.ConversationsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversations_host_no_port(transport_name): @@ -2963,7 +4825,11 @@ def test_conversations_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2971,6 +4837,7 @@ def test_conversations_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversations_host_with_port(transport_name): @@ -2981,7 +4848,48 @@ def test_conversations_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_conversations_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ConversationsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ConversationsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_conversation._session + session2 = client2.transport.create_conversation._session + assert session1 != session2 + session1 = client1.transport.list_conversations._session + session2 = client2.transport.list_conversations._session + assert session1 != session2 + session1 = client1.transport.get_conversation._session + session2 = client2.transport.get_conversation._session + assert session1 != session2 + session1 = client1.transport.complete_conversation._session + session2 = client2.transport.complete_conversation._session + assert session1 != session2 + session1 = client1.transport.list_messages._session + session2 = client2.transport.list_messages._session + assert session1 != session2 + session1 = client1.transport.suggest_conversation_summary._session + session2 = client2.transport.suggest_conversation_summary._session + assert session1 != session2 def test_conversations_grpc_transport_channel(): @@ -3347,6 +5255,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4064,6 +6258,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4081,6 +6276,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_documents.py b/tests/unit/gapic/dialogflow_v2/test_documents.py index 6380c02e1..471a1e2ba 100644 --- a/tests/unit/gapic/dialogflow_v2/test_documents.py +++ b/tests/unit/gapic/dialogflow_v2/test_documents.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -45,6 +47,7 @@ from google.protobuf import any_pb2 # type: ignore from google.protobuf import empty_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore from google.rpc import status_pb2 # type: ignore import grpc @@ -52,6 +55,8 @@ from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.documents import ( DocumentsAsyncClient, @@ -108,6 +113,7 @@ def test__get_default_mtls_endpoint(): [ (DocumentsClient, "grpc"), (DocumentsAsyncClient, "grpc_asyncio"), + (DocumentsClient, "rest"), ], ) def test_documents_client_from_service_account_info(client_class, transport_name): @@ -121,7 +127,11 @@ def test_documents_client_from_service_account_info(client_class, transport_name assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -129,6 +139,7 @@ def test_documents_client_from_service_account_info(client_class, transport_name [ (transports.DocumentsGrpcTransport, "grpc"), (transports.DocumentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.DocumentsRestTransport, "rest"), ], ) def test_documents_client_service_account_always_use_jwt( @@ -154,6 +165,7 @@ def test_documents_client_service_account_always_use_jwt( [ (DocumentsClient, "grpc"), (DocumentsAsyncClient, "grpc_asyncio"), + (DocumentsClient, "rest"), ], ) def test_documents_client_from_service_account_file(client_class, transport_name): @@ -174,13 +186,18 @@ def test_documents_client_from_service_account_file(client_class, transport_name assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_documents_client_get_transport_class(): transport = DocumentsClient.get_transport_class() available_transports = [ transports.DocumentsGrpcTransport, + transports.DocumentsRestTransport, ] assert transport in available_transports @@ -197,6 +214,7 @@ def test_documents_client_get_transport_class(): transports.DocumentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (DocumentsClient, transports.DocumentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -338,6 +356,8 @@ def test_documents_client_client_options(client_class, transport_class, transpor "grpc_asyncio", "false", ), + (DocumentsClient, transports.DocumentsRestTransport, "rest", "true"), + (DocumentsClient, transports.DocumentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -531,6 +551,7 @@ def test_documents_client_get_mtls_endpoint_and_cert_source(client_class): transports.DocumentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (DocumentsClient, transports.DocumentsRestTransport, "rest"), ], ) def test_documents_client_client_options_scopes( @@ -566,6 +587,7 @@ def test_documents_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (DocumentsClient, transports.DocumentsRestTransport, "rest", None), ], ) def test_documents_client_client_options_credentials_file( @@ -2561,168 +2583,2364 @@ async def test_export_document_field_headers_async(): ) in kw["metadata"] -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.DocumentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + document.ListDocumentsRequest, + dict, + ], +) +def test_list_documents_rest(request_type): + client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = DocumentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = document.ListDocumentsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.DocumentsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = document.ListDocumentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_documents(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListDocumentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_documents_rest_required_fields( + request_type=document.ListDocumentsRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_documents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_documents._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "filter", + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = document.ListDocumentsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = document.ListDocumentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_documents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_documents_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - with pytest.raises(ValueError): - client = DocumentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + + unset_fields = transport.list_documents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.DocumentsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_documents_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = DocumentsClient( - client_options=options, - transport=transport, + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.DocumentsRestInterceptor, "post_list_documents" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_list_documents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = document.ListDocumentsRequest.pb(document.ListDocumentsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = document.ListDocumentsResponse.to_json( + document.ListDocumentsResponse() ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = DocumentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = document.ListDocumentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = document.ListDocumentsResponse() + + client.list_documents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.DocumentsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_documents_rest_bad_request( + transport: str = "rest", request_type=document.ListDocumentsRequest +): + client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = DocumentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.DocumentsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_documents(request) + + +def test_list_documents_rest_flattened(): + client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = DocumentsClient(transport=transport) - assert client.transport is transport + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = document.ListDocumentsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.DocumentsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/knowledgeBases/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = document.ListDocumentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_documents(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/knowledgeBases/*}/documents" + % client.transport._host, + args[1], + ) + + +def test_list_documents_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.DocumentsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_documents( + document.ListDocumentsRequest(), + parent="parent_value", + ) + + +def test_list_documents_rest_pager(transport: str = "rest"): + client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + document.ListDocumentsResponse( + documents=[ + document.Document(), + document.Document(), + document.Document(), + ], + next_page_token="abc", + ), + document.ListDocumentsResponse( + documents=[], + next_page_token="def", + ), + document.ListDocumentsResponse( + documents=[ + document.Document(), + ], + next_page_token="ghi", + ), + document.ListDocumentsResponse( + documents=[ + document.Document(), + document.Document(), + ], + ), + ) + # Two responses for two calls + response = response + response -@pytest.mark.parametrize( - "transport_class", - [ - transports.DocumentsGrpcTransport, - transports.DocumentsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + # Wrap the values into proper Response objs + response = tuple(document.ListDocumentsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/knowledgeBases/sample2"} + + pager = client.list_documents(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, document.Document) for i in results) + + pages = list(client.list_documents(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + document.GetDocumentRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = DocumentsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name - - -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. +def test_get_document_rest(request_type): client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.DocumentsGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) -def test_documents_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.DocumentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = document.Document( + name="name_value", + display_name="display_name_value", + mime_type="mime_type_value", + knowledge_types=[document.Document.KnowledgeType.FAQ], + enable_auto_reload=True, + state=document.Document.State.CREATING, + content_uri="content_uri_value", ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = document.Document.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_documents_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.documents.transports.DocumentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.DocumentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_document(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_documents", - "get_document", - "create_document", - "import_documents", - "delete_document", - "update_document", - "reload_document", - "export_document", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + # Establish that the response is the type that we expect. + assert isinstance(response, document.Document) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.mime_type == "mime_type_value" + assert response.knowledge_types == [document.Document.KnowledgeType.FAQ] + assert response.enable_auto_reload is True + assert response.state == document.Document.State.CREATING - with pytest.raises(NotImplementedError): - transport.close() - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client +def test_get_document_rest_required_fields(request_type=document.GetDocumentRequest): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = document.Document() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = document.Document.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_document(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_document_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_document._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_document_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.DocumentsRestInterceptor, "post_get_document" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_get_document" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = document.GetDocumentRequest.pb(document.GetDocumentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = document.Document.to_json(document.Document()) + + request = document.GetDocumentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = document.Document() + + client.get_document( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_document_rest_bad_request( + transport: str = "rest", request_type=document.GetDocumentRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_document(request) + + +def test_get_document_rest_flattened(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = document.Document() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = document.Document.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_document(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/knowledgeBases/*/documents/*}" + % client.transport._host, + args[1], + ) + + +def test_get_document_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_document( + document.GetDocumentRequest(), + name="name_value", + ) + + +def test_get_document_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_document.CreateDocumentRequest, + dict, + ], +) +def test_create_document_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request_init["document"] = { + "name": "name_value", + "display_name": "display_name_value", + "mime_type": "mime_type_value", + "knowledge_types": [1], + "content_uri": "content_uri_value", + "raw_content": b"raw_content_blob", + "enable_auto_reload": True, + "latest_reload_status": { + "time": {"seconds": 751, "nanos": 543}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + "metadata": {}, + "state": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_document(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_create_document_rest_required_fields( + request_type=gcd_document.CreateDocumentRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_document(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_document_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_document._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "document", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_document_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.DocumentsRestInterceptor, "post_create_document" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_create_document" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_document.CreateDocumentRequest.pb( + gcd_document.CreateDocumentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = gcd_document.CreateDocumentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.create_document( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_document_rest_bad_request( + transport: str = "rest", request_type=gcd_document.CreateDocumentRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request_init["document"] = { + "name": "name_value", + "display_name": "display_name_value", + "mime_type": "mime_type_value", + "knowledge_types": [1], + "content_uri": "content_uri_value", + "raw_content": b"raw_content_blob", + "enable_auto_reload": True, + "latest_reload_status": { + "time": {"seconds": 751, "nanos": 543}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + "metadata": {}, + "state": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_document(request) + + +def test_create_document_rest_flattened(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/knowledgeBases/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + document=gcd_document.Document(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_document(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/knowledgeBases/*}/documents" + % client.transport._host, + args[1], + ) + + +def test_create_document_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_document( + gcd_document.CreateDocumentRequest(), + parent="parent_value", + document=gcd_document.Document(name="name_value"), + ) + + +def test_create_document_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + document.ImportDocumentsRequest, + dict, + ], +) +def test_import_documents_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.import_documents(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_import_documents_rest_required_fields( + request_type=document.ImportDocumentsRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).import_documents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).import_documents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.import_documents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_import_documents_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.import_documents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "documentTemplate", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_import_documents_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.DocumentsRestInterceptor, "post_import_documents" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_import_documents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = document.ImportDocumentsRequest.pb( + document.ImportDocumentsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = document.ImportDocumentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.import_documents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_import_documents_rest_bad_request( + transport: str = "rest", request_type=document.ImportDocumentsRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.import_documents(request) + + +def test_import_documents_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + document.DeleteDocumentRequest, + dict, + ], +) +def test_delete_document_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_document(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_delete_document_rest_required_fields( + request_type=document.DeleteDocumentRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_document(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_document_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_document._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_document_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.DocumentsRestInterceptor, "post_delete_document" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_delete_document" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = document.DeleteDocumentRequest.pb(document.DeleteDocumentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = document.DeleteDocumentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.delete_document( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_delete_document_rest_bad_request( + transport: str = "rest", request_type=document.DeleteDocumentRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_document(request) + + +def test_delete_document_rest_flattened(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_document(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/knowledgeBases/*/documents/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_document_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_document( + document.DeleteDocumentRequest(), + name="name_value", + ) + + +def test_delete_document_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_document.UpdateDocumentRequest, + dict, + ], +) +def test_update_document_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "document": { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + } + request_init["document"] = { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3", + "display_name": "display_name_value", + "mime_type": "mime_type_value", + "knowledge_types": [1], + "content_uri": "content_uri_value", + "raw_content": b"raw_content_blob", + "enable_auto_reload": True, + "latest_reload_status": { + "time": {"seconds": 751, "nanos": 543}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + "metadata": {}, + "state": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_document(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_update_document_rest_required_fields( + request_type=gcd_document.UpdateDocumentRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_document._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_document(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_document_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_document._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("document",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_document_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.DocumentsRestInterceptor, "post_update_document" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_update_document" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_document.UpdateDocumentRequest.pb( + gcd_document.UpdateDocumentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = gcd_document.UpdateDocumentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.update_document( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_document_rest_bad_request( + transport: str = "rest", request_type=gcd_document.UpdateDocumentRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "document": { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + } + request_init["document"] = { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3", + "display_name": "display_name_value", + "mime_type": "mime_type_value", + "knowledge_types": [1], + "content_uri": "content_uri_value", + "raw_content": b"raw_content_blob", + "enable_auto_reload": True, + "latest_reload_status": { + "time": {"seconds": 751, "nanos": 543}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + "metadata": {}, + "state": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_document(request) + + +def test_update_document_rest_flattened(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "document": { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + } + + # get truthy value for each flattened field + mock_args = dict( + document=gcd_document.Document(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_document(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{document.name=projects/*/knowledgeBases/*/documents/*}" + % client.transport._host, + args[1], + ) + + +def test_update_document_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_document( + gcd_document.UpdateDocumentRequest(), + document=gcd_document.Document(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_document_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + document.ReloadDocumentRequest, + dict, + ], +) +def test_reload_document_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.reload_document(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_reload_document_rest_required_fields( + request_type=document.ReloadDocumentRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).reload_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).reload_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.reload_document(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_reload_document_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.reload_document._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_reload_document_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.DocumentsRestInterceptor, "post_reload_document" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_reload_document" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = document.ReloadDocumentRequest.pb(document.ReloadDocumentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = document.ReloadDocumentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.reload_document( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_reload_document_rest_bad_request( + transport: str = "rest", request_type=document.ReloadDocumentRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.reload_document(request) + + +def test_reload_document_rest_flattened(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.reload_document(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/knowledgeBases/*/documents/*}:reload" + % client.transport._host, + args[1], + ) + + +def test_reload_document_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.reload_document( + document.ReloadDocumentRequest(), + name="name_value", + content_uri="content_uri_value", + ) + + +def test_reload_document_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + document.ExportDocumentRequest, + dict, + ], +) +def test_export_document_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.export_document(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_export_document_rest_required_fields( + request_type=document.ExportDocumentRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).export_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).export_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.export_document(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_export_document_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.export_document._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_export_document_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.DocumentsRestInterceptor, "post_export_document" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_export_document" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = document.ExportDocumentRequest.pb(document.ExportDocumentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = document.ExportDocumentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.export_document( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_export_document_rest_bad_request( + transport: str = "rest", request_type=document.ExportDocumentRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.export_document(request) + + +def test_export_document_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = DocumentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = DocumentsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = DocumentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = DocumentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = DocumentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.DocumentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.DocumentsGrpcTransport, + transports.DocumentsGrpcAsyncIOTransport, + transports.DocumentsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = DocumentsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.DocumentsGrpcTransport, + ) + + +def test_documents_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.DocumentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_documents_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.documents.transports.DocumentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.DocumentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_documents", + "get_document", + "create_document", + "import_documents", + "delete_document", + "update_document", + "reload_document", + "export_document", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client # Catch all for all remaining methods and properties remainder = [ @@ -2811,6 +5029,7 @@ def test_documents_transport_auth_adc(transport_class): [ transports.DocumentsGrpcTransport, transports.DocumentsGrpcAsyncIOTransport, + transports.DocumentsRestTransport, ], ) def test_documents_transport_auth_gdch_credentials(transport_class): @@ -2908,11 +5127,40 @@ def test_documents_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_documents_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.DocumentsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_documents_rest_lro_client(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_documents_host_no_port(transport_name): @@ -2923,7 +5171,11 @@ def test_documents_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2931,6 +5183,7 @@ def test_documents_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_documents_host_with_port(transport_name): @@ -2941,7 +5194,54 @@ def test_documents_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_documents_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = DocumentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = DocumentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_documents._session + session2 = client2.transport.list_documents._session + assert session1 != session2 + session1 = client1.transport.get_document._session + session2 = client2.transport.get_document._session + assert session1 != session2 + session1 = client1.transport.create_document._session + session2 = client2.transport.create_document._session + assert session1 != session2 + session1 = client1.transport.import_documents._session + session2 = client2.transport.import_documents._session + assert session1 != session2 + session1 = client1.transport.delete_document._session + session2 = client2.transport.delete_document._session + assert session1 != session2 + session1 = client1.transport.update_document._session + session2 = client2.transport.update_document._session + assert session1 != session2 + session1 = client1.transport.reload_document._session + session2 = client2.transport.reload_document._session + assert session1 != session2 + session1 = client1.transport.export_document._session + session2 = client2.transport.export_document._session + assert session1 != session2 def test_documents_grpc_transport_channel(): @@ -3262,6 +5562,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3979,6 +6565,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3996,6 +6583,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_entity_types.py b/tests/unit/gapic/dialogflow_v2/test_entity_types.py index a3bae68cd..dfaa9370d 100644 --- a/tests/unit/gapic/dialogflow_v2/test_entity_types.py +++ b/tests/unit/gapic/dialogflow_v2/test_entity_types.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -44,12 +46,15 @@ from google.oauth2 import service_account from google.protobuf import empty_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.entity_types import ( EntityTypesAsyncClient, @@ -107,6 +112,7 @@ def test__get_default_mtls_endpoint(): [ (EntityTypesClient, "grpc"), (EntityTypesAsyncClient, "grpc_asyncio"), + (EntityTypesClient, "rest"), ], ) def test_entity_types_client_from_service_account_info(client_class, transport_name): @@ -120,7 +126,11 @@ def test_entity_types_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -128,6 +138,7 @@ def test_entity_types_client_from_service_account_info(client_class, transport_n [ (transports.EntityTypesGrpcTransport, "grpc"), (transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.EntityTypesRestTransport, "rest"), ], ) def test_entity_types_client_service_account_always_use_jwt( @@ -153,6 +164,7 @@ def test_entity_types_client_service_account_always_use_jwt( [ (EntityTypesClient, "grpc"), (EntityTypesAsyncClient, "grpc_asyncio"), + (EntityTypesClient, "rest"), ], ) def test_entity_types_client_from_service_account_file(client_class, transport_name): @@ -173,13 +185,18 @@ def test_entity_types_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_entity_types_client_get_transport_class(): transport = EntityTypesClient.get_transport_class() available_transports = [ transports.EntityTypesGrpcTransport, + transports.EntityTypesRestTransport, ] assert transport in available_transports @@ -196,6 +213,7 @@ def test_entity_types_client_get_transport_class(): transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest"), ], ) @mock.patch.object( @@ -339,6 +357,8 @@ def test_entity_types_client_client_options( "grpc_asyncio", "false", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", "true"), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -532,6 +552,7 @@ def test_entity_types_client_get_mtls_endpoint_and_cert_source(client_class): transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest"), ], ) def test_entity_types_client_client_options_scopes( @@ -567,6 +588,7 @@ def test_entity_types_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", None), ], ) def test_entity_types_client_client_options_credentials_file( @@ -3379,127 +3401,2956 @@ async def test_batch_delete_entities_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.EntityTypesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + entity_type.ListEntityTypesRequest, + dict, + ], +) +def test_list_entity_types_rest(request_type): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = EntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = entity_type.ListEntityTypesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.EntityTypesGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.ListEntityTypesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_entity_types(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListEntityTypesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_entity_types_rest_required_fields( + request_type=entity_type.ListEntityTypesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_entity_types._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = entity_type.ListEntityTypesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = entity_type.ListEntityTypesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_entity_types(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_entity_types_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + + unset_fields = transport.list_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.EntityTypesGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_entity_types_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options=options, - transport=transport, + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EntityTypesRestInterceptor, "post_list_entity_types" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_list_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.ListEntityTypesRequest.pb( + entity_type.ListEntityTypesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = entity_type.ListEntityTypesResponse.to_json( + entity_type.ListEntityTypesResponse() ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = entity_type.ListEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = entity_type.ListEntityTypesResponse() + + client.list_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.EntityTypesGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_entity_types_rest_bad_request( + transport: str = "rest", request_type=entity_type.ListEntityTypesRequest +): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.EntityTypesGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_entity_types(request) + + +def test_list_entity_types_rest_flattened(): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = EntityTypesClient(transport=transport) - assert client.transport is transport + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = entity_type.ListEntityTypesResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.EntityTypesGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.ListEntityTypesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_entity_types(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent}/entityTypes" % client.transport._host, + args[1], + ) + + +def test_list_entity_types_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.EntityTypesGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_entity_types( + entity_type.ListEntityTypesRequest(), + parent="parent_value", + language_code="language_code_value", + ) + + +def test_list_entity_types_rest_pager(transport: str = "rest"): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + entity_type.EntityType(), + entity_type.EntityType(), + ], + next_page_token="abc", + ), + entity_type.ListEntityTypesResponse( + entity_types=[], + next_page_token="def", + ), + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + ], + next_page_token="ghi", + ), + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + entity_type.EntityType(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + entity_type.ListEntityTypesResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values -@pytest.mark.parametrize( - "transport_class", - [ - transports.EntityTypesGrpcTransport, - transports.EntityTypesGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1/agent"} + + pager = client.list_entity_types(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, entity_type.EntityType) for i in results) + + pages = list(client.list_entity_types(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + entity_type.GetEntityTypeRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = EntityTypesClient.get_transport_class(transport_name)( +def test_get_entity_type_rest(request_type): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + + +def test_get_entity_type_rest_required_fields( + request_type=entity_type.GetEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = entity_type.EntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.EntityTypesGrpcTransport, + + unset_fields = transport.get_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EntityTypesRestInterceptor, "post_get_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_get_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.GetEntityTypeRequest.pb( + entity_type.GetEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = entity_type.EntityType.to_json( + entity_type.EntityType() + ) + request = entity_type.GetEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = entity_type.EntityType() -def test_entity_types_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.EntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + client.get_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_entity_type_rest_bad_request( + transport: str = "rest", request_type=entity_type.GetEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_entity_type(request) + + +def test_get_entity_type_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/entityTypes/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/agent/entityTypes/*}" % client.transport._host, + args[1], + ) + + +def test_get_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_entity_type( + entity_type.GetEntityTypeRequest(), + name="name_value", + language_code="language_code_value", + ) + + +def test_get_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_entity_type.CreateEntityTypeRequest, + dict, + ], +) +def test_create_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["entity_type"] = { + "name": "name_value", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "enable_fuzzy_extraction": True, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=gcd_entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=gcd_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == gcd_entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == gcd_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + + +def test_create_entity_type_rest_required_fields( + request_type=gcd_entity_type.CreateEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "entityType", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EntityTypesRestInterceptor, "post_create_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_create_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_entity_type.CreateEntityTypeRequest.pb( + gcd_entity_type.CreateEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_entity_type.EntityType.to_json( + gcd_entity_type.EntityType() + ) + + request = gcd_entity_type.CreateEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_entity_type.EntityType() + + client.create_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_entity_type_rest_bad_request( + transport: str = "rest", request_type=gcd_entity_type.CreateEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["entity_type"] = { + "name": "name_value", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "enable_fuzzy_extraction": True, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_entity_type(request) + + +def test_create_entity_type_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entity_type=gcd_entity_type.EntityType(name="name_value"), + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent}/entityTypes" % client.transport._host, + args[1], + ) + + +def test_create_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_entity_type( + gcd_entity_type.CreateEntityTypeRequest(), + parent="parent_value", + entity_type=gcd_entity_type.EntityType(name="name_value"), + language_code="language_code_value", + ) + + +def test_create_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_entity_type.UpdateEntityTypeRequest, + dict, + ], +) +def test_update_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "entity_type": {"name": "projects/sample1/agent/entityTypes/sample2"} + } + request_init["entity_type"] = { + "name": "projects/sample1/agent/entityTypes/sample2", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "enable_fuzzy_extraction": True, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=gcd_entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=gcd_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == gcd_entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == gcd_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + + +def test_update_entity_type_rest_required_fields( + request_type=gcd_entity_type.UpdateEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("entityType",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EntityTypesRestInterceptor, "post_update_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_update_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_entity_type.UpdateEntityTypeRequest.pb( + gcd_entity_type.UpdateEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_entity_type.EntityType.to_json( + gcd_entity_type.EntityType() + ) + + request = gcd_entity_type.UpdateEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_entity_type.EntityType() + + client.update_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_entity_type_rest_bad_request( + transport: str = "rest", request_type=gcd_entity_type.UpdateEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "entity_type": {"name": "projects/sample1/agent/entityTypes/sample2"} + } + request_init["entity_type"] = { + "name": "projects/sample1/agent/entityTypes/sample2", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "enable_fuzzy_extraction": True, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_entity_type(request) + + +def test_update_entity_type_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "entity_type": {"name": "projects/sample1/agent/entityTypes/sample2"} + } + + # get truthy value for each flattened field + mock_args = dict( + entity_type=gcd_entity_type.EntityType(name="name_value"), + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{entity_type.name=projects/*/agent/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_update_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_entity_type( + gcd_entity_type.UpdateEntityTypeRequest(), + entity_type=gcd_entity_type.EntityType(name="name_value"), + language_code="language_code_value", + ) + + +def test_update_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.DeleteEntityTypeRequest, + dict, + ], +) +def test_delete_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_entity_type(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_entity_type_rest_required_fields( + request_type=entity_type.DeleteEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_delete_entity_type" + ) as pre: + pre.assert_not_called() + pb_message = entity_type.DeleteEntityTypeRequest.pb( + entity_type.DeleteEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = entity_type.DeleteEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_entity_type_rest_bad_request( + transport: str = "rest", request_type=entity_type.DeleteEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_entity_type(request) + + +def test_delete_entity_type_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/entityTypes/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/agent/entityTypes/*}" % client.transport._host, + args[1], + ) + + +def test_delete_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_entity_type( + entity_type.DeleteEntityTypeRequest(), + name="name_value", + ) + + +def test_delete_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.BatchUpdateEntityTypesRequest, + dict, + ], +) +def test_batch_update_entity_types_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_update_entity_types(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_update_entity_types_rest_required_fields( + request_type=entity_type.BatchUpdateEntityTypesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_update_entity_types(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_update_entity_types_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_update_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_update_entity_types_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.EntityTypesRestInterceptor, "post_batch_update_entity_types" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_batch_update_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.BatchUpdateEntityTypesRequest.pb( + entity_type.BatchUpdateEntityTypesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = entity_type.BatchUpdateEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_update_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_update_entity_types_rest_bad_request( + transport: str = "rest", request_type=entity_type.BatchUpdateEntityTypesRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_update_entity_types(request) + + +def test_batch_update_entity_types_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.BatchDeleteEntityTypesRequest, + dict, + ], +) +def test_batch_delete_entity_types_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_delete_entity_types(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_delete_entity_types_rest_required_fields( + request_type=entity_type.BatchDeleteEntityTypesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["entity_type_names"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + jsonified_request["entityTypeNames"] = "entity_type_names_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + assert "entityTypeNames" in jsonified_request + assert jsonified_request["entityTypeNames"] == "entity_type_names_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_delete_entity_types(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_delete_entity_types_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_delete_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "entityTypeNames", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_delete_entity_types_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.EntityTypesRestInterceptor, "post_batch_delete_entity_types" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_batch_delete_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.BatchDeleteEntityTypesRequest.pb( + entity_type.BatchDeleteEntityTypesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = entity_type.BatchDeleteEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_delete_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_delete_entity_types_rest_bad_request( + transport: str = "rest", request_type=entity_type.BatchDeleteEntityTypesRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_delete_entity_types(request) + + +def test_batch_delete_entity_types_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entity_type_names=["entity_type_names_value"], + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_delete_entity_types(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent}/entityTypes:batchDelete" + % client.transport._host, + args[1], + ) + + +def test_batch_delete_entity_types_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_delete_entity_types( + entity_type.BatchDeleteEntityTypesRequest(), + parent="parent_value", + entity_type_names=["entity_type_names_value"], + ) + + +def test_batch_delete_entity_types_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.BatchCreateEntitiesRequest, + dict, + ], +) +def test_batch_create_entities_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_create_entities(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_create_entities_rest_required_fields( + request_type=entity_type.BatchCreateEntitiesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_create_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_create_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_create_entities(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_create_entities_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_create_entities._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "entities", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_create_entities_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.EntityTypesRestInterceptor, "post_batch_create_entities" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_batch_create_entities" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.BatchCreateEntitiesRequest.pb( + entity_type.BatchCreateEntitiesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = entity_type.BatchCreateEntitiesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_create_entities( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_create_entities_rest_bad_request( + transport: str = "rest", request_type=entity_type.BatchCreateEntitiesRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_create_entities(request) + + +def test_batch_create_entities_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/entityTypes/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entities=[entity_type.EntityType.Entity(value="value_value")], + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_create_entities(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent/entityTypes/*}/entities:batchCreate" + % client.transport._host, + args[1], + ) + + +def test_batch_create_entities_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_create_entities( + entity_type.BatchCreateEntitiesRequest(), + parent="parent_value", + entities=[entity_type.EntityType.Entity(value="value_value")], + language_code="language_code_value", + ) + + +def test_batch_create_entities_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.BatchUpdateEntitiesRequest, + dict, + ], +) +def test_batch_update_entities_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_update_entities(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_update_entities_rest_required_fields( + request_type=entity_type.BatchUpdateEntitiesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_update_entities(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_update_entities_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_update_entities._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "entities", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_update_entities_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.EntityTypesRestInterceptor, "post_batch_update_entities" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_batch_update_entities" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.BatchUpdateEntitiesRequest.pb( + entity_type.BatchUpdateEntitiesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = entity_type.BatchUpdateEntitiesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_update_entities( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_update_entities_rest_bad_request( + transport: str = "rest", request_type=entity_type.BatchUpdateEntitiesRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_update_entities(request) + + +def test_batch_update_entities_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/entityTypes/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entities=[entity_type.EntityType.Entity(value="value_value")], + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_update_entities(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent/entityTypes/*}/entities:batchUpdate" + % client.transport._host, + args[1], + ) + + +def test_batch_update_entities_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_update_entities( + entity_type.BatchUpdateEntitiesRequest(), + parent="parent_value", + entities=[entity_type.EntityType.Entity(value="value_value")], + language_code="language_code_value", + ) + + +def test_batch_update_entities_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.BatchDeleteEntitiesRequest, + dict, + ], +) +def test_batch_delete_entities_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_delete_entities(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_delete_entities_rest_required_fields( + request_type=entity_type.BatchDeleteEntitiesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["entity_values"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + jsonified_request["entityValues"] = "entity_values_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + assert "entityValues" in jsonified_request + assert jsonified_request["entityValues"] == "entity_values_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_delete_entities(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_delete_entities_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_delete_entities._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "entityValues", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_delete_entities_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.EntityTypesRestInterceptor, "post_batch_delete_entities" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_batch_delete_entities" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.BatchDeleteEntitiesRequest.pb( + entity_type.BatchDeleteEntitiesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = entity_type.BatchDeleteEntitiesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_delete_entities( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_delete_entities_rest_bad_request( + transport: str = "rest", request_type=entity_type.BatchDeleteEntitiesRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_delete_entities(request) + + +def test_batch_delete_entities_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/entityTypes/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entity_values=["entity_values_value"], + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_delete_entities(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent/entityTypes/*}/entities:batchDelete" + % client.transport._host, + args[1], + ) + + +def test_batch_delete_entities_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_delete_entities( + entity_type.BatchDeleteEntitiesRequest(), + parent="parent_value", + entity_values=["entity_values_value"], + language_code="language_code_value", + ) + + +def test_batch_delete_entities_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = EntityTypesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.EntityTypesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.EntityTypesGrpcTransport, + transports.EntityTypesGrpcAsyncIOTransport, + transports.EntityTypesRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = EntityTypesClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.EntityTypesGrpcTransport, + ) + + +def test_entity_types_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.EntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", ) @@ -3631,6 +6482,7 @@ def test_entity_types_transport_auth_adc(transport_class): [ transports.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport, + transports.EntityTypesRestTransport, ], ) def test_entity_types_transport_auth_gdch_credentials(transport_class): @@ -3728,11 +6580,40 @@ def test_entity_types_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_entity_types_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.EntityTypesRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_entity_types_rest_lro_client(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_entity_types_host_no_port(transport_name): @@ -3743,7 +6624,11 @@ def test_entity_types_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3751,6 +6636,7 @@ def test_entity_types_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_entity_types_host_with_port(transport_name): @@ -3761,7 +6647,60 @@ def test_entity_types_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_entity_types_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = EntityTypesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = EntityTypesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_entity_types._session + session2 = client2.transport.list_entity_types._session + assert session1 != session2 + session1 = client1.transport.get_entity_type._session + session2 = client2.transport.get_entity_type._session + assert session1 != session2 + session1 = client1.transport.create_entity_type._session + session2 = client2.transport.create_entity_type._session + assert session1 != session2 + session1 = client1.transport.update_entity_type._session + session2 = client2.transport.update_entity_type._session + assert session1 != session2 + session1 = client1.transport.delete_entity_type._session + session2 = client2.transport.delete_entity_type._session + assert session1 != session2 + session1 = client1.transport.batch_update_entity_types._session + session2 = client2.transport.batch_update_entity_types._session + assert session1 != session2 + session1 = client1.transport.batch_delete_entity_types._session + session2 = client2.transport.batch_delete_entity_types._session + assert session1 != session2 + session1 = client1.transport.batch_create_entities._session + session2 = client2.transport.batch_create_entities._session + assert session1 != session2 + session1 = client1.transport.batch_update_entities._session + session2 = client2.transport.batch_update_entities._session + assert session1 != session2 + session1 = client1.transport.batch_delete_entities._session + session2 = client2.transport.batch_delete_entities._session + assert session1 != session2 def test_entity_types_grpc_transport_channel(): @@ -4079,6 +7018,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4796,6 +8021,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4813,6 +8039,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_environments.py b/tests/unit/gapic/dialogflow_v2/test_environments.py index 5a4c722d2..8dde4ff1f 100644 --- a/tests/unit/gapic/dialogflow_v2/test_environments.py +++ b/tests/unit/gapic/dialogflow_v2/test_environments.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,12 +36,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.environments import ( EnvironmentsAsyncClient, @@ -96,6 +101,7 @@ def test__get_default_mtls_endpoint(): [ (EnvironmentsClient, "grpc"), (EnvironmentsAsyncClient, "grpc_asyncio"), + (EnvironmentsClient, "rest"), ], ) def test_environments_client_from_service_account_info(client_class, transport_name): @@ -109,7 +115,11 @@ def test_environments_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -117,6 +127,7 @@ def test_environments_client_from_service_account_info(client_class, transport_n [ (transports.EnvironmentsGrpcTransport, "grpc"), (transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.EnvironmentsRestTransport, "rest"), ], ) def test_environments_client_service_account_always_use_jwt( @@ -142,6 +153,7 @@ def test_environments_client_service_account_always_use_jwt( [ (EnvironmentsClient, "grpc"), (EnvironmentsAsyncClient, "grpc_asyncio"), + (EnvironmentsClient, "rest"), ], ) def test_environments_client_from_service_account_file(client_class, transport_name): @@ -162,13 +174,18 @@ def test_environments_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_environments_client_get_transport_class(): transport = EnvironmentsClient.get_transport_class() available_transports = [ transports.EnvironmentsGrpcTransport, + transports.EnvironmentsRestTransport, ] assert transport in available_transports @@ -185,6 +202,7 @@ def test_environments_client_get_transport_class(): transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -328,6 +346,8 @@ def test_environments_client_client_options( "grpc_asyncio", "false", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", "true"), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -521,6 +541,7 @@ def test_environments_client_get_mtls_endpoint_and_cert_source(client_class): transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest"), ], ) def test_environments_client_client_options_scopes( @@ -561,6 +582,7 @@ def test_environments_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", None), ], ) def test_environments_client_client_options_credentials_file( @@ -2135,138 +2157,1764 @@ async def test_get_environment_history_async_pages(): assert page_.raw_page.next_page_token == token -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.EnvironmentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + environment.ListEnvironmentsRequest, + dict, + ], +) +def test_list_environments_rest(request_type): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.ListEnvironmentsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.ListEnvironmentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_environments(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListEnvironmentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_environments_rest_required_fields( + request_type=environment.ListEnvironmentsRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_environments._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_environments._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.ListEnvironmentsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = environment.ListEnvironmentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_environments(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_environments_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_environments._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_environments_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options=options, - transport=transport, + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "post_list_environments" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_list_environments" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.ListEnvironmentsRequest.pb( + environment.ListEnvironmentsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = environment.ListEnvironmentsResponse.to_json( + environment.ListEnvironmentsResponse() ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = environment.ListEnvironmentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.ListEnvironmentsResponse() + + client.list_environments( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_environments_rest_bad_request( + transport: str = "rest", request_type=environment.ListEnvironmentsRequest +): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.EnvironmentsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_environments(request) + + +def test_list_environments_rest_flattened(): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = EnvironmentsClient(transport=transport) - assert client.transport is transport + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.ListEnvironmentsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.EnvironmentsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.ListEnvironmentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_environments(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent}/environments" % client.transport._host, + args[1], + ) + + +def test_list_environments_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.EnvironmentsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_environments( + environment.ListEnvironmentsRequest(), + parent="parent_value", + ) + + +def test_list_environments_rest_pager(transport: str = "rest"): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + environment.Environment(), + environment.Environment(), + ], + next_page_token="abc", + ), + environment.ListEnvironmentsResponse( + environments=[], + next_page_token="def", + ), + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + ], + next_page_token="ghi", + ), + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + environment.Environment(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + environment.ListEnvironmentsResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values -@pytest.mark.parametrize( - "transport_class", - [ - transports.EnvironmentsGrpcTransport, - transports.EnvironmentsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1/agent"} + + pager = client.list_environments(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, environment.Environment) for i in results) + + pages = list(client.list_environments(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + environment.GetEnvironmentRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = EnvironmentsClient.get_transport_class(transport_name)( +def test_get_environment_rest(request_type): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.Environment( + name="name_value", + description="description_value", + agent_version="agent_version_value", + state=environment.Environment.State.STOPPED, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_environment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, environment.Environment) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.agent_version == "agent_version_value" + assert response.state == environment.Environment.State.STOPPED + + +def test_get_environment_rest_required_fields( + request_type=environment.GetEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert isinstance( - client.transport, - transports.EnvironmentsGrpcTransport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.Environment() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) + unset_fields = transport.get_environment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) -def test_environments_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.EnvironmentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "post_get_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_get_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.GetEnvironmentRequest.pb( + environment.GetEnvironmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = environment.Environment.to_json( + environment.Environment() + ) -def test_environments_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.environments.transports.EnvironmentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.EnvironmentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + request = environment.GetEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.Environment() + + client.get_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_environment_rest_bad_request( + transport: str = "rest", request_type=environment.GetEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_environment(request) + + +def test_get_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.CreateEnvironmentRequest, + dict, + ], +) +def test_create_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["environment"] = { + "name": "name_value", + "description": "description_value", + "agent_version": "agent_version_value", + "state": 1, + "update_time": {"seconds": 751, "nanos": 543}, + "text_to_speech_settings": { + "enable_text_to_speech": True, + "output_audio_encoding": 1, + "sample_rate_hertz": 1817, + "synthesize_speech_configs": {}, + }, + "fulfillment": { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.Environment( + name="name_value", + description="description_value", + agent_version="agent_version_value", + state=environment.Environment.State.STOPPED, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_environment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, environment.Environment) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.agent_version == "agent_version_value" + assert response.state == environment.Environment.State.STOPPED + + +def test_create_environment_rest_required_fields( + request_type=environment.CreateEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["environment_id"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + assert "environmentId" not in jsonified_request + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + assert "environmentId" in jsonified_request + assert jsonified_request["environmentId"] == request_init["environment_id"] + + jsonified_request["parent"] = "parent_value" + jsonified_request["environmentId"] = "environment_id_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_environment._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("environment_id",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + assert "environmentId" in jsonified_request + assert jsonified_request["environmentId"] == "environment_id_value" + + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.Environment() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_environment(request) + + expected_params = [ + ( + "environmentId", + "", + ), + ("$alt", "json;enum-encoding=int"), + ] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_environment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("environmentId",)) + & set( + ( + "parent", + "environment", + "environmentId", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "post_create_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_create_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.CreateEnvironmentRequest.pb( + environment.CreateEnvironmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = environment.Environment.to_json( + environment.Environment() + ) + + request = environment.CreateEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.Environment() + + client.create_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_environment_rest_bad_request( + transport: str = "rest", request_type=environment.CreateEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["environment"] = { + "name": "name_value", + "description": "description_value", + "agent_version": "agent_version_value", + "state": 1, + "update_time": {"seconds": 751, "nanos": 543}, + "text_to_speech_settings": { + "enable_text_to_speech": True, + "output_audio_encoding": 1, + "sample_rate_hertz": 1817, + "synthesize_speech_configs": {}, + }, + "fulfillment": { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_environment(request) + + +def test_create_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.UpdateEnvironmentRequest, + dict, + ], +) +def test_update_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": {"name": "projects/sample1/agent/environments/sample2"} + } + request_init["environment"] = { + "name": "projects/sample1/agent/environments/sample2", + "description": "description_value", + "agent_version": "agent_version_value", + "state": 1, + "update_time": {"seconds": 751, "nanos": 543}, + "text_to_speech_settings": { + "enable_text_to_speech": True, + "output_audio_encoding": 1, + "sample_rate_hertz": 1817, + "synthesize_speech_configs": {}, + }, + "fulfillment": { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.Environment( + name="name_value", + description="description_value", + agent_version="agent_version_value", + state=environment.Environment.State.STOPPED, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_environment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, environment.Environment) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.agent_version == "agent_version_value" + assert response.state == environment.Environment.State.STOPPED + + +def test_update_environment_rest_required_fields( + request_type=environment.UpdateEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_environment._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "allow_load_to_draft_and_discard_changes", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.Environment() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_environment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "allowLoadToDraftAndDiscardChanges", + "updateMask", + ) + ) + & set( + ( + "environment", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "post_update_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_update_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.UpdateEnvironmentRequest.pb( + environment.UpdateEnvironmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = environment.Environment.to_json( + environment.Environment() + ) + + request = environment.UpdateEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.Environment() + + client.update_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_environment_rest_bad_request( + transport: str = "rest", request_type=environment.UpdateEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": {"name": "projects/sample1/agent/environments/sample2"} + } + request_init["environment"] = { + "name": "projects/sample1/agent/environments/sample2", + "description": "description_value", + "agent_version": "agent_version_value", + "state": 1, + "update_time": {"seconds": 751, "nanos": 543}, + "text_to_speech_settings": { + "enable_text_to_speech": True, + "output_audio_encoding": 1, + "sample_rate_hertz": 1817, + "synthesize_speech_configs": {}, + }, + "fulfillment": { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_environment(request) + + +def test_update_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.DeleteEnvironmentRequest, + dict, + ], +) +def test_delete_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_environment(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_environment_rest_required_fields( + request_type=environment.DeleteEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_environment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_delete_environment" + ) as pre: + pre.assert_not_called() + pb_message = environment.DeleteEnvironmentRequest.pb( + environment.DeleteEnvironmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = environment.DeleteEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_environment_rest_bad_request( + transport: str = "rest", request_type=environment.DeleteEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_environment(request) + + +def test_delete_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.GetEnvironmentHistoryRequest, + dict, + ], +) +def test_get_environment_history_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.EnvironmentHistory( + parent="parent_value", + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.EnvironmentHistory.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_environment_history(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.GetEnvironmentHistoryPager) + assert response.parent == "parent_value" + assert response.next_page_token == "next_page_token_value" + + +def test_get_environment_history_rest_required_fields( + request_type=environment.GetEnvironmentHistoryRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_environment_history._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_environment_history._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.EnvironmentHistory() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = environment.EnvironmentHistory.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_environment_history(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_environment_history_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_environment_history._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_environment_history_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "post_get_environment_history" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_get_environment_history" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.GetEnvironmentHistoryRequest.pb( + environment.GetEnvironmentHistoryRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = environment.EnvironmentHistory.to_json( + environment.EnvironmentHistory() + ) + + request = environment.GetEnvironmentHistoryRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.EnvironmentHistory() + + client.get_environment_history( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_environment_history_rest_bad_request( + transport: str = "rest", request_type=environment.GetEnvironmentHistoryRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_environment_history(request) + + +def test_get_environment_history_rest_pager(transport: str = "rest"): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + environment.EnvironmentHistory( + entries=[ + environment.EnvironmentHistory.Entry(), + environment.EnvironmentHistory.Entry(), + environment.EnvironmentHistory.Entry(), + ], + next_page_token="abc", + ), + environment.EnvironmentHistory( + entries=[], + next_page_token="def", + ), + environment.EnvironmentHistory( + entries=[ + environment.EnvironmentHistory.Entry(), + ], + next_page_token="ghi", + ), + environment.EnvironmentHistory( + entries=[ + environment.EnvironmentHistory.Entry(), + environment.EnvironmentHistory.Entry(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(environment.EnvironmentHistory.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/agent/environments/sample2"} + + pager = client.get_environment_history(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, environment.EnvironmentHistory.Entry) for i in results) + + pages = list(client.get_environment_history(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = EnvironmentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.EnvironmentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.EnvironmentsGrpcTransport, + transports.EnvironmentsGrpcAsyncIOTransport, + transports.EnvironmentsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = EnvironmentsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.EnvironmentsGrpcTransport, + ) + + +def test_environments_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.EnvironmentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_environments_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.environments.transports.EnvironmentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.EnvironmentsTransport( + credentials=ga_credentials.AnonymousCredentials(), ) # Every method on the transport should just blindly @@ -2378,6 +4026,7 @@ def test_environments_transport_auth_adc(transport_class): [ transports.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport, + transports.EnvironmentsRestTransport, ], ) def test_environments_transport_auth_gdch_credentials(transport_class): @@ -2475,11 +4124,23 @@ def test_environments_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_environments_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.EnvironmentsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_environments_host_no_port(transport_name): @@ -2490,7 +4151,11 @@ def test_environments_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2498,6 +4163,7 @@ def test_environments_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_environments_host_with_port(transport_name): @@ -2508,7 +4174,48 @@ def test_environments_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_environments_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = EnvironmentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = EnvironmentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_environments._session + session2 = client2.transport.list_environments._session + assert session1 != session2 + session1 = client1.transport.get_environment._session + session2 = client2.transport.get_environment._session + assert session1 != session2 + session1 = client1.transport.create_environment._session + session2 = client2.transport.create_environment._session + assert session1 != session2 + session1 = client1.transport.update_environment._session + session2 = client2.transport.update_environment._session + assert session1 != session2 + session1 = client1.transport.delete_environment._session + session2 = client2.transport.delete_environment._session + assert session1 != session2 + session1 = client1.transport.get_environment_history._session + session2 = client2.transport.get_environment_history._session + assert session1 != session2 def test_environments_grpc_transport_channel(): @@ -2835,6 +4542,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3552,6 +5545,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3569,6 +5563,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_fulfillments.py b/tests/unit/gapic/dialogflow_v2/test_fulfillments.py index 584b13a92..779ef8fb1 100644 --- a/tests/unit/gapic/dialogflow_v2/test_fulfillments.py +++ b/tests/unit/gapic/dialogflow_v2/test_fulfillments.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,11 +36,14 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.fulfillments import ( FulfillmentsAsyncClient, @@ -95,6 +100,7 @@ def test__get_default_mtls_endpoint(): [ (FulfillmentsClient, "grpc"), (FulfillmentsAsyncClient, "grpc_asyncio"), + (FulfillmentsClient, "rest"), ], ) def test_fulfillments_client_from_service_account_info(client_class, transport_name): @@ -108,7 +114,11 @@ def test_fulfillments_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -116,6 +126,7 @@ def test_fulfillments_client_from_service_account_info(client_class, transport_n [ (transports.FulfillmentsGrpcTransport, "grpc"), (transports.FulfillmentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.FulfillmentsRestTransport, "rest"), ], ) def test_fulfillments_client_service_account_always_use_jwt( @@ -141,6 +152,7 @@ def test_fulfillments_client_service_account_always_use_jwt( [ (FulfillmentsClient, "grpc"), (FulfillmentsAsyncClient, "grpc_asyncio"), + (FulfillmentsClient, "rest"), ], ) def test_fulfillments_client_from_service_account_file(client_class, transport_name): @@ -161,13 +173,18 @@ def test_fulfillments_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_fulfillments_client_get_transport_class(): transport = FulfillmentsClient.get_transport_class() available_transports = [ transports.FulfillmentsGrpcTransport, + transports.FulfillmentsRestTransport, ] assert transport in available_transports @@ -184,6 +201,7 @@ def test_fulfillments_client_get_transport_class(): transports.FulfillmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (FulfillmentsClient, transports.FulfillmentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -327,6 +345,8 @@ def test_fulfillments_client_client_options( "grpc_asyncio", "false", ), + (FulfillmentsClient, transports.FulfillmentsRestTransport, "rest", "true"), + (FulfillmentsClient, transports.FulfillmentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -520,6 +540,7 @@ def test_fulfillments_client_get_mtls_endpoint_and_cert_source(client_class): transports.FulfillmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (FulfillmentsClient, transports.FulfillmentsRestTransport, "rest"), ], ) def test_fulfillments_client_client_options_scopes( @@ -560,6 +581,7 @@ def test_fulfillments_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (FulfillmentsClient, transports.FulfillmentsRestTransport, "rest", None), ], ) def test_fulfillments_client_client_options_credentials_file( @@ -1184,6 +1206,589 @@ async def test_update_fulfillment_flattened_error_async(): ) +@pytest.mark.parametrize( + "request_type", + [ + fulfillment.GetFulfillmentRequest, + dict, + ], +) +def test_get_fulfillment_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/fulfillment"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = fulfillment.Fulfillment( + name="name_value", + display_name="display_name_value", + enabled=True, + generic_web_service=fulfillment.Fulfillment.GenericWebService( + uri="uri_value" + ), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_fulfillment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, fulfillment.Fulfillment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.enabled is True + + +def test_get_fulfillment_rest_required_fields( + request_type=fulfillment.GetFulfillmentRequest, +): + transport_class = transports.FulfillmentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_fulfillment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_fulfillment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = fulfillment.Fulfillment() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_fulfillment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_fulfillment_rest_unset_required_fields(): + transport = transports.FulfillmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_fulfillment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_fulfillment_rest_interceptors(null_interceptor): + transport = transports.FulfillmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.FulfillmentsRestInterceptor(), + ) + client = FulfillmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.FulfillmentsRestInterceptor, "post_get_fulfillment" + ) as post, mock.patch.object( + transports.FulfillmentsRestInterceptor, "pre_get_fulfillment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = fulfillment.GetFulfillmentRequest.pb( + fulfillment.GetFulfillmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = fulfillment.Fulfillment.to_json( + fulfillment.Fulfillment() + ) + + request = fulfillment.GetFulfillmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = fulfillment.Fulfillment() + + client.get_fulfillment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_fulfillment_rest_bad_request( + transport: str = "rest", request_type=fulfillment.GetFulfillmentRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/fulfillment"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_fulfillment(request) + + +def test_get_fulfillment_rest_flattened(): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = fulfillment.Fulfillment() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/fulfillment"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_fulfillment(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/agent/fulfillment}" % client.transport._host, + args[1], + ) + + +def test_get_fulfillment_rest_flattened_error(transport: str = "rest"): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_fulfillment( + fulfillment.GetFulfillmentRequest(), + name="name_value", + ) + + +def test_get_fulfillment_rest_error(): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_fulfillment.UpdateFulfillmentRequest, + dict, + ], +) +def test_update_fulfillment_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"fulfillment": {"name": "projects/sample1/agent/fulfillment"}} + request_init["fulfillment"] = { + "name": "projects/sample1/agent/fulfillment", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_fulfillment.Fulfillment( + name="name_value", + display_name="display_name_value", + enabled=True, + generic_web_service=gcd_fulfillment.Fulfillment.GenericWebService( + uri="uri_value" + ), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_fulfillment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_fulfillment.Fulfillment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.enabled is True + + +def test_update_fulfillment_rest_required_fields( + request_type=gcd_fulfillment.UpdateFulfillmentRequest, +): + transport_class = transports.FulfillmentsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_fulfillment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_fulfillment._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_fulfillment.Fulfillment() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_fulfillment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_fulfillment_rest_unset_required_fields(): + transport = transports.FulfillmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_fulfillment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "fulfillment", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_fulfillment_rest_interceptors(null_interceptor): + transport = transports.FulfillmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.FulfillmentsRestInterceptor(), + ) + client = FulfillmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.FulfillmentsRestInterceptor, "post_update_fulfillment" + ) as post, mock.patch.object( + transports.FulfillmentsRestInterceptor, "pre_update_fulfillment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_fulfillment.UpdateFulfillmentRequest.pb( + gcd_fulfillment.UpdateFulfillmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_fulfillment.Fulfillment.to_json( + gcd_fulfillment.Fulfillment() + ) + + request = gcd_fulfillment.UpdateFulfillmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_fulfillment.Fulfillment() + + client.update_fulfillment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_fulfillment_rest_bad_request( + transport: str = "rest", request_type=gcd_fulfillment.UpdateFulfillmentRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"fulfillment": {"name": "projects/sample1/agent/fulfillment"}} + request_init["fulfillment"] = { + "name": "projects/sample1/agent/fulfillment", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_fulfillment(request) + + +def test_update_fulfillment_rest_flattened(): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_fulfillment.Fulfillment() + + # get arguments that satisfy an http rule for this method + sample_request = {"fulfillment": {"name": "projects/sample1/agent/fulfillment"}} + + # get truthy value for each flattened field + mock_args = dict( + fulfillment=gcd_fulfillment.Fulfillment(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_fulfillment(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{fulfillment.name=projects/*/agent/fulfillment}" + % client.transport._host, + args[1], + ) + + +def test_update_fulfillment_rest_flattened_error(transport: str = "rest"): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_fulfillment( + gcd_fulfillment.UpdateFulfillmentRequest(), + fulfillment=gcd_fulfillment.Fulfillment(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_fulfillment_rest_error(): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.FulfillmentsGrpcTransport( @@ -1265,6 +1870,7 @@ def test_transport_get_channel(): [ transports.FulfillmentsGrpcTransport, transports.FulfillmentsGrpcAsyncIOTransport, + transports.FulfillmentsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1279,6 +1885,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1423,6 +2030,7 @@ def test_fulfillments_transport_auth_adc(transport_class): [ transports.FulfillmentsGrpcTransport, transports.FulfillmentsGrpcAsyncIOTransport, + transports.FulfillmentsRestTransport, ], ) def test_fulfillments_transport_auth_gdch_credentials(transport_class): @@ -1520,11 +2128,23 @@ def test_fulfillments_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_fulfillments_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.FulfillmentsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_fulfillments_host_no_port(transport_name): @@ -1535,7 +2155,11 @@ def test_fulfillments_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1543,6 +2167,7 @@ def test_fulfillments_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_fulfillments_host_with_port(transport_name): @@ -1553,7 +2178,36 @@ def test_fulfillments_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_fulfillments_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = FulfillmentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = FulfillmentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.get_fulfillment._session + session2 = client2.transport.get_fulfillment._session + assert session1 != session2 + session1 = client1.transport.update_fulfillment._session + session2 = client2.transport.update_fulfillment._session + assert session1 != session2 def test_fulfillments_grpc_transport_channel(): @@ -1834,6 +2488,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = FulfillmentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2551,6 +3491,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2568,6 +3509,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_intents.py b/tests/unit/gapic/dialogflow_v2/test_intents.py index aaf8af3e3..08f9304f4 100644 --- a/tests/unit/gapic/dialogflow_v2/test_intents.py +++ b/tests/unit/gapic/dialogflow_v2/test_intents.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -44,12 +46,15 @@ from google.oauth2 import service_account from google.protobuf import empty_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.intents import ( IntentsAsyncClient, @@ -105,6 +110,7 @@ def test__get_default_mtls_endpoint(): [ (IntentsClient, "grpc"), (IntentsAsyncClient, "grpc_asyncio"), + (IntentsClient, "rest"), ], ) def test_intents_client_from_service_account_info(client_class, transport_name): @@ -118,7 +124,11 @@ def test_intents_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -126,6 +136,7 @@ def test_intents_client_from_service_account_info(client_class, transport_name): [ (transports.IntentsGrpcTransport, "grpc"), (transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.IntentsRestTransport, "rest"), ], ) def test_intents_client_service_account_always_use_jwt(transport_class, transport_name): @@ -149,6 +160,7 @@ def test_intents_client_service_account_always_use_jwt(transport_class, transpor [ (IntentsClient, "grpc"), (IntentsAsyncClient, "grpc_asyncio"), + (IntentsClient, "rest"), ], ) def test_intents_client_from_service_account_file(client_class, transport_name): @@ -169,13 +181,18 @@ def test_intents_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_intents_client_get_transport_class(): transport = IntentsClient.get_transport_class() available_transports = [ transports.IntentsGrpcTransport, + transports.IntentsRestTransport, ] assert transport in available_transports @@ -188,6 +205,7 @@ def test_intents_client_get_transport_class(): [ (IntentsClient, transports.IntentsGrpcTransport, "grpc"), (IntentsAsyncClient, transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (IntentsClient, transports.IntentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -327,6 +345,8 @@ def test_intents_client_client_options(client_class, transport_class, transport_ "grpc_asyncio", "false", ), + (IntentsClient, transports.IntentsRestTransport, "rest", "true"), + (IntentsClient, transports.IntentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -512,6 +532,7 @@ def test_intents_client_get_mtls_endpoint_and_cert_source(client_class): [ (IntentsClient, transports.IntentsGrpcTransport, "grpc"), (IntentsAsyncClient, transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (IntentsClient, transports.IntentsRestTransport, "rest"), ], ) def test_intents_client_client_options_scopes( @@ -547,6 +568,7 @@ def test_intents_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (IntentsClient, transports.IntentsRestTransport, "rest", None), ], ) def test_intents_client_client_options_credentials_file( @@ -2743,257 +2765,2967 @@ async def test_batch_delete_intents_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.IntentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + intent.ListIntentsRequest, + dict, + ], +) +def test_list_intents_rest(request_type): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = IntentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.IntentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = IntentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.IntentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = IntentsClient( - client_options=options, - transport=transport, + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = intent.ListIntentsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = IntentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.ListIntentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.IntentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = IntentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_intents(request) + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListIntentsPager) + assert response.next_page_token == "next_page_token_value" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.IntentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - client = IntentsClient(transport=transport) - assert client.transport is transport +def test_list_intents_rest_required_fields(request_type=intent.ListIntentsRequest): + transport_class = transports.IntentsRestTransport -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.IntentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - channel = transport.grpc_channel - assert channel - transport = transports.IntentsGrpcAsyncIOTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - channel = transport.grpc_channel - assert channel + # verify fields with default values are dropped + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_intents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) -@pytest.mark.parametrize( - "transport_class", - [ - transports.IntentsGrpcTransport, - transports.IntentsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + # verify required fields with default values are now present + jsonified_request["parent"] = "parent_value" -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = IntentsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_intents._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "intent_view", + "language_code", + "page_size", + "page_token", + ) ) - assert transport.kind == transport_name + jsonified_request.update(unset_fields) + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = intent.ListIntentsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = intent.ListIntentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_intents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_intents_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.IntentsGrpcTransport, + + unset_fields = transport.list_intents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "intentView", + "languageCode", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) ) -def test_intents_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.IntentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_intents_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.IntentsRestInterceptor, "post_list_intents" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_list_intents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.ListIntentsRequest.pb(intent.ListIntentsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = intent.ListIntentsResponse.to_json( + intent.ListIntentsResponse() ) + request = intent.ListIntentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = intent.ListIntentsResponse() -def test_intents_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.intents.transports.IntentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.IntentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_intents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_intents", - "get_intent", - "create_intent", - "update_intent", - "delete_intent", - "batch_update_intents", - "batch_delete_intents", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + pre.assert_called_once() + post.assert_called_once() - with pytest.raises(NotImplementedError): - transport.close() - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client +def test_list_intents_rest_bad_request( + transport: str = "rest", request_type=intent.ListIntentsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_intents(request) -def test_intents_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.dialogflow_v2.services.intents.transports.IntentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.IntentsTransport( - credentials_file="credentials.json", - quota_project_id="octopus", - ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", - ) +def test_list_intents_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) -def test_intents_base_transport_with_adc(): - # Test the default credentials are used if credentials and credentials_file are None. - with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( - "google.cloud.dialogflow_v2.services.intents.transports.IntentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.IntentsTransport() - adc.assert_called_once() + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = intent.ListIntentsResponse() + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} -def test_intents_auth_adc(): - # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - IntentsClient() - adc.assert_called_once_with( - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id=None, + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + language_code="language_code_value", ) + mock_args.update(sample_request) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.ListIntentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value -@pytest.mark.parametrize( - "transport_class", - [ - transports.IntentsGrpcTransport, - transports.IntentsGrpcAsyncIOTransport, - ], -) -def test_intents_transport_auth_adc(transport_class): - # If credentials and host are not provided, the transport class should use - # ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class(quota_project_id="octopus", scopes=["1", "2"]) - adc.assert_called_once_with( - scopes=["1", "2"], - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", + client.list_intents(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent}/intents" % client.transport._host, args[1] ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.IntentsGrpcTransport, - transports.IntentsGrpcAsyncIOTransport, - ], -) +def test_list_intents_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_intents( + intent.ListIntentsRequest(), + parent="parent_value", + language_code="language_code_value", + ) + + +def test_list_intents_rest_pager(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + intent.Intent(), + intent.Intent(), + ], + next_page_token="abc", + ), + intent.ListIntentsResponse( + intents=[], + next_page_token="def", + ), + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + ], + next_page_token="ghi", + ), + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + intent.Intent(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(intent.ListIntentsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/agent"} + + pager = client.list_intents(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, intent.Intent) for i in results) + + pages = list(client.list_intents(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + intent.GetIntentRequest, + dict, + ], +) +def test_get_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/intents/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = intent.Intent( + name="name_value", + display_name="display_name_value", + webhook_state=intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED, + priority=898, + is_fallback=True, + ml_disabled=True, + live_agent_handoff=True, + end_interaction=True, + input_context_names=["input_context_names_value"], + events=["events_value"], + action="action_value", + reset_contexts=True, + default_response_platforms=[intent.Intent.Message.Platform.FACEBOOK], + root_followup_intent_name="root_followup_intent_name_value", + parent_followup_intent_name="parent_followup_intent_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.webhook_state == intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED + assert response.priority == 898 + assert response.is_fallback is True + assert response.ml_disabled is True + assert response.live_agent_handoff is True + assert response.end_interaction is True + assert response.input_context_names == ["input_context_names_value"] + assert response.events == ["events_value"] + assert response.action == "action_value" + assert response.reset_contexts is True + assert response.default_response_platforms == [ + intent.Intent.Message.Platform.FACEBOOK + ] + assert response.root_followup_intent_name == "root_followup_intent_name_value" + assert response.parent_followup_intent_name == "parent_followup_intent_name_value" + + +def test_get_intent_rest_required_fields(request_type=intent.GetIntentRequest): + transport_class = transports.IntentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "intent_view", + "language_code", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = intent.Intent() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "intentView", + "languageCode", + ) + ) + & set(("name",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.IntentsRestInterceptor, "post_get_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_get_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.GetIntentRequest.pb(intent.GetIntentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = intent.Intent.to_json(intent.Intent()) + + request = intent.GetIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = intent.Intent() + + client.get_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_intent_rest_bad_request( + transport: str = "rest", request_type=intent.GetIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/intents/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_intent(request) + + +def test_get_intent_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/intents/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_intent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/agent/intents/*}" % client.transport._host, args[1] + ) + + +def test_get_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_intent( + intent.GetIntentRequest(), + name="name_value", + language_code="language_code_value", + ) + + +def test_get_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_intent.CreateIntentRequest, + dict, + ], +) +def test_create_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["intent"] = { + "name": "name_value", + "display_name": "display_name_value", + "webhook_state": 1, + "priority": 898, + "is_fallback": True, + "ml_disabled": True, + "live_agent_handoff": True, + "end_interaction": True, + "input_context_names": [ + "input_context_names_value1", + "input_context_names_value2", + ], + "events": ["events_value1", "events_value2"], + "training_phrases": [ + { + "name": "name_value", + "type_": 1, + "parts": [ + { + "text": "text_value", + "entity_type": "entity_type_value", + "alias": "alias_value", + "user_defined": True, + } + ], + "times_added_count": 1787, + } + ], + "action": "action_value", + "output_contexts": [ + {"name": "name_value", "lifespan_count": 1498, "parameters": {"fields": {}}} + ], + "reset_contexts": True, + "parameters": [ + { + "name": "name_value", + "display_name": "display_name_value", + "value": "value_value", + "default_value": "default_value_value", + "entity_type_display_name": "entity_type_display_name_value", + "mandatory": True, + "prompts": ["prompts_value1", "prompts_value2"], + "is_list": True, + } + ], + "messages": [ + { + "text": {"text": ["text_value1", "text_value2"]}, + "image": { + "image_uri": "image_uri_value", + "accessibility_text": "accessibility_text_value", + }, + "quick_replies": { + "title": "title_value", + "quick_replies": ["quick_replies_value1", "quick_replies_value2"], + }, + "card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image_uri": "image_uri_value", + "buttons": [{"text": "text_value", "postback": "postback_value"}], + }, + "payload": {}, + "simple_responses": { + "simple_responses": [ + { + "text_to_speech": "text_to_speech_value", + "ssml": "ssml_value", + "display_text": "display_text_value", + } + ] + }, + "basic_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "formatted_text": "formatted_text_value", + "image": {}, + "buttons": [ + { + "title": "title_value", + "open_uri_action": {"uri": "uri_value"}, + } + ], + }, + "suggestions": {"suggestions": [{"title": "title_value"}]}, + "link_out_suggestion": { + "destination_name": "destination_name_value", + "uri": "uri_value", + }, + "list_select": { + "title": "title_value", + "items": [ + { + "info": { + "key": "key_value", + "synonyms": ["synonyms_value1", "synonyms_value2"], + }, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ], + "subtitle": "subtitle_value", + }, + "carousel_select": { + "items": [ + { + "info": {}, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ] + }, + "browse_carousel_card": { + "items": [ + { + "open_uri_action": {"url": "url_value", "url_type_hint": 1}, + "title": "title_value", + "description": "description_value", + "image": {}, + "footer": "footer_value", + } + ], + "image_display_options": 1, + }, + "table_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image": {}, + "column_properties": [ + {"header": "header_value", "horizontal_alignment": 1} + ], + "rows": [ + {"cells": [{"text": "text_value"}], "divider_after": True} + ], + "buttons": {}, + }, + "media_content": { + "media_type": 1, + "media_objects": [ + { + "name": "name_value", + "description": "description_value", + "large_image": {}, + "icon": {}, + "content_url": "content_url_value", + } + ], + }, + "platform": 1, + } + ], + "default_response_platforms": [1], + "root_followup_intent_name": "root_followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + "followup_intent_info": [ + { + "followup_intent_name": "followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + } + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent( + name="name_value", + display_name="display_name_value", + webhook_state=gcd_intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED, + priority=898, + is_fallback=True, + ml_disabled=True, + live_agent_handoff=True, + end_interaction=True, + input_context_names=["input_context_names_value"], + events=["events_value"], + action="action_value", + reset_contexts=True, + default_response_platforms=[gcd_intent.Intent.Message.Platform.FACEBOOK], + root_followup_intent_name="root_followup_intent_name_value", + parent_followup_intent_name="parent_followup_intent_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert ( + response.webhook_state == gcd_intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED + ) + assert response.priority == 898 + assert response.is_fallback is True + assert response.ml_disabled is True + assert response.live_agent_handoff is True + assert response.end_interaction is True + assert response.input_context_names == ["input_context_names_value"] + assert response.events == ["events_value"] + assert response.action == "action_value" + assert response.reset_contexts is True + assert response.default_response_platforms == [ + gcd_intent.Intent.Message.Platform.FACEBOOK + ] + assert response.root_followup_intent_name == "root_followup_intent_name_value" + assert response.parent_followup_intent_name == "parent_followup_intent_name_value" + + +def test_create_intent_rest_required_fields( + request_type=gcd_intent.CreateIntentRequest, +): + transport_class = transports.IntentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "intent_view", + "language_code", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "intentView", + "languageCode", + ) + ) + & set( + ( + "parent", + "intent", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.IntentsRestInterceptor, "post_create_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_create_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_intent.CreateIntentRequest.pb(gcd_intent.CreateIntentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_intent.Intent.to_json(gcd_intent.Intent()) + + request = gcd_intent.CreateIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_intent.Intent() + + client.create_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_intent_rest_bad_request( + transport: str = "rest", request_type=gcd_intent.CreateIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["intent"] = { + "name": "name_value", + "display_name": "display_name_value", + "webhook_state": 1, + "priority": 898, + "is_fallback": True, + "ml_disabled": True, + "live_agent_handoff": True, + "end_interaction": True, + "input_context_names": [ + "input_context_names_value1", + "input_context_names_value2", + ], + "events": ["events_value1", "events_value2"], + "training_phrases": [ + { + "name": "name_value", + "type_": 1, + "parts": [ + { + "text": "text_value", + "entity_type": "entity_type_value", + "alias": "alias_value", + "user_defined": True, + } + ], + "times_added_count": 1787, + } + ], + "action": "action_value", + "output_contexts": [ + {"name": "name_value", "lifespan_count": 1498, "parameters": {"fields": {}}} + ], + "reset_contexts": True, + "parameters": [ + { + "name": "name_value", + "display_name": "display_name_value", + "value": "value_value", + "default_value": "default_value_value", + "entity_type_display_name": "entity_type_display_name_value", + "mandatory": True, + "prompts": ["prompts_value1", "prompts_value2"], + "is_list": True, + } + ], + "messages": [ + { + "text": {"text": ["text_value1", "text_value2"]}, + "image": { + "image_uri": "image_uri_value", + "accessibility_text": "accessibility_text_value", + }, + "quick_replies": { + "title": "title_value", + "quick_replies": ["quick_replies_value1", "quick_replies_value2"], + }, + "card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image_uri": "image_uri_value", + "buttons": [{"text": "text_value", "postback": "postback_value"}], + }, + "payload": {}, + "simple_responses": { + "simple_responses": [ + { + "text_to_speech": "text_to_speech_value", + "ssml": "ssml_value", + "display_text": "display_text_value", + } + ] + }, + "basic_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "formatted_text": "formatted_text_value", + "image": {}, + "buttons": [ + { + "title": "title_value", + "open_uri_action": {"uri": "uri_value"}, + } + ], + }, + "suggestions": {"suggestions": [{"title": "title_value"}]}, + "link_out_suggestion": { + "destination_name": "destination_name_value", + "uri": "uri_value", + }, + "list_select": { + "title": "title_value", + "items": [ + { + "info": { + "key": "key_value", + "synonyms": ["synonyms_value1", "synonyms_value2"], + }, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ], + "subtitle": "subtitle_value", + }, + "carousel_select": { + "items": [ + { + "info": {}, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ] + }, + "browse_carousel_card": { + "items": [ + { + "open_uri_action": {"url": "url_value", "url_type_hint": 1}, + "title": "title_value", + "description": "description_value", + "image": {}, + "footer": "footer_value", + } + ], + "image_display_options": 1, + }, + "table_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image": {}, + "column_properties": [ + {"header": "header_value", "horizontal_alignment": 1} + ], + "rows": [ + {"cells": [{"text": "text_value"}], "divider_after": True} + ], + "buttons": {}, + }, + "media_content": { + "media_type": 1, + "media_objects": [ + { + "name": "name_value", + "description": "description_value", + "large_image": {}, + "icon": {}, + "content_url": "content_url_value", + } + ], + }, + "platform": 1, + } + ], + "default_response_platforms": [1], + "root_followup_intent_name": "root_followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + "followup_intent_info": [ + { + "followup_intent_name": "followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + } + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_intent(request) + + +def test_create_intent_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + intent=gcd_intent.Intent(name="name_value"), + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_intent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent}/intents" % client.transport._host, args[1] + ) + + +def test_create_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_intent( + gcd_intent.CreateIntentRequest(), + parent="parent_value", + intent=gcd_intent.Intent(name="name_value"), + language_code="language_code_value", + ) + + +def test_create_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_intent.UpdateIntentRequest, + dict, + ], +) +def test_update_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"intent": {"name": "projects/sample1/agent/intents/sample2"}} + request_init["intent"] = { + "name": "projects/sample1/agent/intents/sample2", + "display_name": "display_name_value", + "webhook_state": 1, + "priority": 898, + "is_fallback": True, + "ml_disabled": True, + "live_agent_handoff": True, + "end_interaction": True, + "input_context_names": [ + "input_context_names_value1", + "input_context_names_value2", + ], + "events": ["events_value1", "events_value2"], + "training_phrases": [ + { + "name": "name_value", + "type_": 1, + "parts": [ + { + "text": "text_value", + "entity_type": "entity_type_value", + "alias": "alias_value", + "user_defined": True, + } + ], + "times_added_count": 1787, + } + ], + "action": "action_value", + "output_contexts": [ + {"name": "name_value", "lifespan_count": 1498, "parameters": {"fields": {}}} + ], + "reset_contexts": True, + "parameters": [ + { + "name": "name_value", + "display_name": "display_name_value", + "value": "value_value", + "default_value": "default_value_value", + "entity_type_display_name": "entity_type_display_name_value", + "mandatory": True, + "prompts": ["prompts_value1", "prompts_value2"], + "is_list": True, + } + ], + "messages": [ + { + "text": {"text": ["text_value1", "text_value2"]}, + "image": { + "image_uri": "image_uri_value", + "accessibility_text": "accessibility_text_value", + }, + "quick_replies": { + "title": "title_value", + "quick_replies": ["quick_replies_value1", "quick_replies_value2"], + }, + "card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image_uri": "image_uri_value", + "buttons": [{"text": "text_value", "postback": "postback_value"}], + }, + "payload": {}, + "simple_responses": { + "simple_responses": [ + { + "text_to_speech": "text_to_speech_value", + "ssml": "ssml_value", + "display_text": "display_text_value", + } + ] + }, + "basic_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "formatted_text": "formatted_text_value", + "image": {}, + "buttons": [ + { + "title": "title_value", + "open_uri_action": {"uri": "uri_value"}, + } + ], + }, + "suggestions": {"suggestions": [{"title": "title_value"}]}, + "link_out_suggestion": { + "destination_name": "destination_name_value", + "uri": "uri_value", + }, + "list_select": { + "title": "title_value", + "items": [ + { + "info": { + "key": "key_value", + "synonyms": ["synonyms_value1", "synonyms_value2"], + }, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ], + "subtitle": "subtitle_value", + }, + "carousel_select": { + "items": [ + { + "info": {}, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ] + }, + "browse_carousel_card": { + "items": [ + { + "open_uri_action": {"url": "url_value", "url_type_hint": 1}, + "title": "title_value", + "description": "description_value", + "image": {}, + "footer": "footer_value", + } + ], + "image_display_options": 1, + }, + "table_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image": {}, + "column_properties": [ + {"header": "header_value", "horizontal_alignment": 1} + ], + "rows": [ + {"cells": [{"text": "text_value"}], "divider_after": True} + ], + "buttons": {}, + }, + "media_content": { + "media_type": 1, + "media_objects": [ + { + "name": "name_value", + "description": "description_value", + "large_image": {}, + "icon": {}, + "content_url": "content_url_value", + } + ], + }, + "platform": 1, + } + ], + "default_response_platforms": [1], + "root_followup_intent_name": "root_followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + "followup_intent_info": [ + { + "followup_intent_name": "followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + } + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent( + name="name_value", + display_name="display_name_value", + webhook_state=gcd_intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED, + priority=898, + is_fallback=True, + ml_disabled=True, + live_agent_handoff=True, + end_interaction=True, + input_context_names=["input_context_names_value"], + events=["events_value"], + action="action_value", + reset_contexts=True, + default_response_platforms=[gcd_intent.Intent.Message.Platform.FACEBOOK], + root_followup_intent_name="root_followup_intent_name_value", + parent_followup_intent_name="parent_followup_intent_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert ( + response.webhook_state == gcd_intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED + ) + assert response.priority == 898 + assert response.is_fallback is True + assert response.ml_disabled is True + assert response.live_agent_handoff is True + assert response.end_interaction is True + assert response.input_context_names == ["input_context_names_value"] + assert response.events == ["events_value"] + assert response.action == "action_value" + assert response.reset_contexts is True + assert response.default_response_platforms == [ + gcd_intent.Intent.Message.Platform.FACEBOOK + ] + assert response.root_followup_intent_name == "root_followup_intent_name_value" + assert response.parent_followup_intent_name == "parent_followup_intent_name_value" + + +def test_update_intent_rest_required_fields( + request_type=gcd_intent.UpdateIntentRequest, +): + transport_class = transports.IntentsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "intent_view", + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "intentView", + "languageCode", + "updateMask", + ) + ) + & set(("intent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.IntentsRestInterceptor, "post_update_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_update_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_intent.UpdateIntentRequest.pb(gcd_intent.UpdateIntentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_intent.Intent.to_json(gcd_intent.Intent()) + + request = gcd_intent.UpdateIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_intent.Intent() + + client.update_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_intent_rest_bad_request( + transport: str = "rest", request_type=gcd_intent.UpdateIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"intent": {"name": "projects/sample1/agent/intents/sample2"}} + request_init["intent"] = { + "name": "projects/sample1/agent/intents/sample2", + "display_name": "display_name_value", + "webhook_state": 1, + "priority": 898, + "is_fallback": True, + "ml_disabled": True, + "live_agent_handoff": True, + "end_interaction": True, + "input_context_names": [ + "input_context_names_value1", + "input_context_names_value2", + ], + "events": ["events_value1", "events_value2"], + "training_phrases": [ + { + "name": "name_value", + "type_": 1, + "parts": [ + { + "text": "text_value", + "entity_type": "entity_type_value", + "alias": "alias_value", + "user_defined": True, + } + ], + "times_added_count": 1787, + } + ], + "action": "action_value", + "output_contexts": [ + {"name": "name_value", "lifespan_count": 1498, "parameters": {"fields": {}}} + ], + "reset_contexts": True, + "parameters": [ + { + "name": "name_value", + "display_name": "display_name_value", + "value": "value_value", + "default_value": "default_value_value", + "entity_type_display_name": "entity_type_display_name_value", + "mandatory": True, + "prompts": ["prompts_value1", "prompts_value2"], + "is_list": True, + } + ], + "messages": [ + { + "text": {"text": ["text_value1", "text_value2"]}, + "image": { + "image_uri": "image_uri_value", + "accessibility_text": "accessibility_text_value", + }, + "quick_replies": { + "title": "title_value", + "quick_replies": ["quick_replies_value1", "quick_replies_value2"], + }, + "card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image_uri": "image_uri_value", + "buttons": [{"text": "text_value", "postback": "postback_value"}], + }, + "payload": {}, + "simple_responses": { + "simple_responses": [ + { + "text_to_speech": "text_to_speech_value", + "ssml": "ssml_value", + "display_text": "display_text_value", + } + ] + }, + "basic_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "formatted_text": "formatted_text_value", + "image": {}, + "buttons": [ + { + "title": "title_value", + "open_uri_action": {"uri": "uri_value"}, + } + ], + }, + "suggestions": {"suggestions": [{"title": "title_value"}]}, + "link_out_suggestion": { + "destination_name": "destination_name_value", + "uri": "uri_value", + }, + "list_select": { + "title": "title_value", + "items": [ + { + "info": { + "key": "key_value", + "synonyms": ["synonyms_value1", "synonyms_value2"], + }, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ], + "subtitle": "subtitle_value", + }, + "carousel_select": { + "items": [ + { + "info": {}, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ] + }, + "browse_carousel_card": { + "items": [ + { + "open_uri_action": {"url": "url_value", "url_type_hint": 1}, + "title": "title_value", + "description": "description_value", + "image": {}, + "footer": "footer_value", + } + ], + "image_display_options": 1, + }, + "table_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image": {}, + "column_properties": [ + {"header": "header_value", "horizontal_alignment": 1} + ], + "rows": [ + {"cells": [{"text": "text_value"}], "divider_after": True} + ], + "buttons": {}, + }, + "media_content": { + "media_type": 1, + "media_objects": [ + { + "name": "name_value", + "description": "description_value", + "large_image": {}, + "icon": {}, + "content_url": "content_url_value", + } + ], + }, + "platform": 1, + } + ], + "default_response_platforms": [1], + "root_followup_intent_name": "root_followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + "followup_intent_info": [ + { + "followup_intent_name": "followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + } + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_intent(request) + + +def test_update_intent_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = {"intent": {"name": "projects/sample1/agent/intents/sample2"}} + + # get truthy value for each flattened field + mock_args = dict( + intent=gcd_intent.Intent(name="name_value"), + language_code="language_code_value", + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_intent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{intent.name=projects/*/agent/intents/*}" % client.transport._host, + args[1], + ) + + +def test_update_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_intent( + gcd_intent.UpdateIntentRequest(), + intent=gcd_intent.Intent(name="name_value"), + language_code="language_code_value", + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + intent.DeleteIntentRequest, + dict, + ], +) +def test_delete_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/intents/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_intent(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_intent_rest_required_fields(request_type=intent.DeleteIntentRequest): + transport_class = transports.IntentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_intent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.IntentsRestInterceptor, "pre_delete_intent" + ) as pre: + pre.assert_not_called() + pb_message = intent.DeleteIntentRequest.pb(intent.DeleteIntentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = intent.DeleteIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_intent_rest_bad_request( + transport: str = "rest", request_type=intent.DeleteIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/intents/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_intent(request) + + +def test_delete_intent_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/intents/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_intent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/agent/intents/*}" % client.transport._host, args[1] + ) + + +def test_delete_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_intent( + intent.DeleteIntentRequest(), + name="name_value", + ) + + +def test_delete_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + intent.BatchUpdateIntentsRequest, + dict, + ], +) +def test_batch_update_intents_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_update_intents(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_update_intents_rest_required_fields( + request_type=intent.BatchUpdateIntentsRequest, +): + transport_class = transports.IntentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_intents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_intents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_update_intents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_update_intents_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_update_intents._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_update_intents_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.IntentsRestInterceptor, "post_batch_update_intents" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_batch_update_intents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.BatchUpdateIntentsRequest.pb( + intent.BatchUpdateIntentsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = intent.BatchUpdateIntentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_update_intents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_update_intents_rest_bad_request( + transport: str = "rest", request_type=intent.BatchUpdateIntentsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_update_intents(request) + + +def test_batch_update_intents_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_update_intents(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent}/intents:batchUpdate" + % client.transport._host, + args[1], + ) + + +def test_batch_update_intents_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_update_intents( + intent.BatchUpdateIntentsRequest(), + parent="parent_value", + intent_batch_uri="intent_batch_uri_value", + intent_batch_inline=intent.IntentBatch( + intents=[intent.Intent(name="name_value")] + ), + ) + + +def test_batch_update_intents_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + intent.BatchDeleteIntentsRequest, + dict, + ], +) +def test_batch_delete_intents_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_delete_intents(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_delete_intents_rest_required_fields( + request_type=intent.BatchDeleteIntentsRequest, +): + transport_class = transports.IntentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_intents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_intents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_delete_intents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_delete_intents_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_delete_intents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "intents", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_delete_intents_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.IntentsRestInterceptor, "post_batch_delete_intents" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_batch_delete_intents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.BatchDeleteIntentsRequest.pb( + intent.BatchDeleteIntentsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = intent.BatchDeleteIntentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_delete_intents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_delete_intents_rest_bad_request( + transport: str = "rest", request_type=intent.BatchDeleteIntentsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_delete_intents(request) + + +def test_batch_delete_intents_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + intents=[intent.Intent(name="name_value")], + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_delete_intents(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent}/intents:batchDelete" + % client.transport._host, + args[1], + ) + + +def test_batch_delete_intents_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_delete_intents( + intent.BatchDeleteIntentsRequest(), + parent="parent_value", + intents=[intent.Intent(name="name_value")], + ) + + +def test_batch_delete_intents_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = IntentsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = IntentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = IntentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.IntentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.IntentsGrpcTransport, + transports.IntentsGrpcAsyncIOTransport, + transports.IntentsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = IntentsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.IntentsGrpcTransport, + ) + + +def test_intents_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.IntentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_intents_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.intents.transports.IntentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.IntentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_intents", + "get_intent", + "create_intent", + "update_intent", + "delete_intent", + "batch_update_intents", + "batch_delete_intents", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_intents_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.dialogflow_v2.services.intents.transports.IntentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.IntentsTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_intents_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.dialogflow_v2.services.intents.transports.IntentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.IntentsTransport() + adc.assert_called_once() + + +def test_intents_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + IntentsClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.IntentsGrpcTransport, + transports.IntentsGrpcAsyncIOTransport, + ], +) +def test_intents_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.IntentsGrpcTransport, + transports.IntentsGrpcAsyncIOTransport, + transports.IntentsRestTransport, + ], +) def test_intents_transport_auth_gdch_credentials(transport_class): host = "https://language.com" api_audience_tests = [None, "https://language2.com"] @@ -3089,11 +5821,40 @@ def test_intents_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_intents_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.IntentsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_intents_rest_lro_client(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_intents_host_no_port(transport_name): @@ -3104,7 +5865,11 @@ def test_intents_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3112,6 +5877,7 @@ def test_intents_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_intents_host_with_port(transport_name): @@ -3122,7 +5888,51 @@ def test_intents_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_intents_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = IntentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = IntentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_intents._session + session2 = client2.transport.list_intents._session + assert session1 != session2 + session1 = client1.transport.get_intent._session + session2 = client2.transport.get_intent._session + assert session1 != session2 + session1 = client1.transport.create_intent._session + session2 = client2.transport.create_intent._session + assert session1 != session2 + session1 = client1.transport.update_intent._session + session2 = client2.transport.update_intent._session + assert session1 != session2 + session1 = client1.transport.delete_intent._session + session2 = client2.transport.delete_intent._session + assert session1 != session2 + session1 = client1.transport.batch_update_intents._session + session2 = client2.transport.batch_update_intents._session + assert session1 != session2 + session1 = client1.transport.batch_delete_intents._session + session2 = client2.transport.batch_delete_intents._session + assert session1 != session2 def test_intents_grpc_transport_channel(): @@ -3466,6 +6276,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4183,6 +7279,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4200,6 +7297,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_knowledge_bases.py b/tests/unit/gapic/dialogflow_v2/test_knowledge_bases.py index eb82c33f8..87c775d92 100644 --- a/tests/unit/gapic/dialogflow_v2/test_knowledge_bases.py +++ b/tests/unit/gapic/dialogflow_v2/test_knowledge_bases.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,11 +36,14 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.knowledge_bases import ( KnowledgeBasesAsyncClient, @@ -99,6 +104,7 @@ def test__get_default_mtls_endpoint(): [ (KnowledgeBasesClient, "grpc"), (KnowledgeBasesAsyncClient, "grpc_asyncio"), + (KnowledgeBasesClient, "rest"), ], ) def test_knowledge_bases_client_from_service_account_info(client_class, transport_name): @@ -112,7 +118,11 @@ def test_knowledge_bases_client_from_service_account_info(client_class, transpor assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -120,6 +130,7 @@ def test_knowledge_bases_client_from_service_account_info(client_class, transpor [ (transports.KnowledgeBasesGrpcTransport, "grpc"), (transports.KnowledgeBasesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.KnowledgeBasesRestTransport, "rest"), ], ) def test_knowledge_bases_client_service_account_always_use_jwt( @@ -145,6 +156,7 @@ def test_knowledge_bases_client_service_account_always_use_jwt( [ (KnowledgeBasesClient, "grpc"), (KnowledgeBasesAsyncClient, "grpc_asyncio"), + (KnowledgeBasesClient, "rest"), ], ) def test_knowledge_bases_client_from_service_account_file(client_class, transport_name): @@ -165,13 +177,18 @@ def test_knowledge_bases_client_from_service_account_file(client_class, transpor assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_knowledge_bases_client_get_transport_class(): transport = KnowledgeBasesClient.get_transport_class() available_transports = [ transports.KnowledgeBasesGrpcTransport, + transports.KnowledgeBasesRestTransport, ] assert transport in available_transports @@ -188,6 +205,7 @@ def test_knowledge_bases_client_get_transport_class(): transports.KnowledgeBasesGrpcAsyncIOTransport, "grpc_asyncio", ), + (KnowledgeBasesClient, transports.KnowledgeBasesRestTransport, "rest"), ], ) @mock.patch.object( @@ -333,6 +351,8 @@ def test_knowledge_bases_client_client_options( "grpc_asyncio", "false", ), + (KnowledgeBasesClient, transports.KnowledgeBasesRestTransport, "rest", "true"), + (KnowledgeBasesClient, transports.KnowledgeBasesRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -532,6 +552,7 @@ def test_knowledge_bases_client_get_mtls_endpoint_and_cert_source(client_class): transports.KnowledgeBasesGrpcAsyncIOTransport, "grpc_asyncio", ), + (KnowledgeBasesClient, transports.KnowledgeBasesRestTransport, "rest"), ], ) def test_knowledge_bases_client_client_options_scopes( @@ -572,6 +593,7 @@ def test_knowledge_bases_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (KnowledgeBasesClient, transports.KnowledgeBasesRestTransport, "rest", None), ], ) def test_knowledge_bases_client_client_options_credentials_file( @@ -2149,208 +2171,1652 @@ async def test_update_knowledge_base_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.KnowledgeBasesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + knowledge_base.ListKnowledgeBasesRequest, + dict, + ], +) +def test_list_knowledge_bases_rest(request_type): + client = KnowledgeBasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = KnowledgeBasesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.KnowledgeBasesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = KnowledgeBasesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.KnowledgeBasesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = KnowledgeBasesClient( - client_options=options, - transport=transport, + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = knowledge_base.ListKnowledgeBasesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = KnowledgeBasesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = knowledge_base.ListKnowledgeBasesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.KnowledgeBasesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_knowledge_bases(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListKnowledgeBasesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_knowledge_bases_rest_required_fields( + request_type=knowledge_base.ListKnowledgeBasesRequest, +): + transport_class = transports.KnowledgeBasesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - with pytest.raises(ValueError): - client = KnowledgeBasesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_knowledge_bases._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_knowledge_bases._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "filter", + "page_size", + "page_token", ) + ) + jsonified_request.update(unset_fields) + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.KnowledgeBasesGrpcTransport( + client = KnowledgeBasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = KnowledgeBasesClient(transport=transport) - assert client.transport is transport + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = knowledge_base.ListKnowledgeBasesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + response_value = Response() + response_value.status_code = 200 -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.KnowledgeBasesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + pb_return_value = knowledge_base.ListKnowledgeBasesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_knowledge_bases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_knowledge_bases_rest_unset_required_fields(): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - channel = transport.grpc_channel - assert channel - transport = transports.KnowledgeBasesGrpcAsyncIOTransport( + unset_fields = transport.list_knowledge_bases._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_knowledge_bases_rest_interceptors(null_interceptor): + transport = transports.KnowledgeBasesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.KnowledgeBasesRestInterceptor(), ) - channel = transport.grpc_channel - assert channel + client = KnowledgeBasesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "post_list_knowledge_bases" + ) as post, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "pre_list_knowledge_bases" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = knowledge_base.ListKnowledgeBasesRequest.pb( + knowledge_base.ListKnowledgeBasesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = knowledge_base.ListKnowledgeBasesResponse.to_json( + knowledge_base.ListKnowledgeBasesResponse() + ) + request = knowledge_base.ListKnowledgeBasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = knowledge_base.ListKnowledgeBasesResponse() -@pytest.mark.parametrize( - "transport_class", - [ - transports.KnowledgeBasesGrpcTransport, - transports.KnowledgeBasesGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + client.list_knowledge_bases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + pre.assert_called_once() + post.assert_called_once() -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = KnowledgeBasesClient.get_transport_class(transport_name)( + +def test_list_knowledge_bases_rest_bad_request( + transport: str = "rest", request_type=knowledge_base.ListKnowledgeBasesRequest +): + client = KnowledgeBasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_knowledge_bases(request) + + +def test_list_knowledge_bases_rest_flattened(): client = KnowledgeBasesClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.KnowledgeBasesGrpcTransport, + transport="rest", ) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = knowledge_base.ListKnowledgeBasesResponse() -def test_knowledge_bases_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.KnowledgeBasesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", ) + mock_args.update(sample_request) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = knowledge_base.ListKnowledgeBasesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value -def test_knowledge_bases_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.knowledge_bases.transports.KnowledgeBasesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.KnowledgeBasesTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_knowledge_bases(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/knowledgeBases" % client.transport._host, args[1] ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_knowledge_bases", - "get_knowledge_base", - "create_knowledge_base", - "delete_knowledge_base", - "update_knowledge_base", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + +def test_list_knowledge_bases_rest_flattened_error(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_knowledge_bases( + knowledge_base.ListKnowledgeBasesRequest(), + parent="parent_value", + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() +def test_list_knowledge_bases_rest_pager(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) -def test_knowledge_bases_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.dialogflow_v2.services.knowledge_bases.transports.KnowledgeBasesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.KnowledgeBasesTransport( - credentials_file="credentials.json", - quota_project_id="octopus", - ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + knowledge_base.ListKnowledgeBasesResponse( + knowledge_bases=[ + knowledge_base.KnowledgeBase(), + knowledge_base.KnowledgeBase(), + knowledge_base.KnowledgeBase(), + ], + next_page_token="abc", + ), + knowledge_base.ListKnowledgeBasesResponse( + knowledge_bases=[], + next_page_token="def", + ), + knowledge_base.ListKnowledgeBasesResponse( + knowledge_bases=[ + knowledge_base.KnowledgeBase(), + ], + next_page_token="ghi", + ), + knowledge_base.ListKnowledgeBasesResponse( + knowledge_bases=[ + knowledge_base.KnowledgeBase(), + knowledge_base.KnowledgeBase(), + ], ), - quota_project_id="octopus", ) + # Two responses for two calls + response = response + response + # Wrap the values into proper Response objs + response = tuple( + knowledge_base.ListKnowledgeBasesResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values -def test_knowledge_bases_base_transport_with_adc(): - # Test the default credentials are used if credentials and credentials_file are None. - with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( - "google.cloud.dialogflow_v2.services.knowledge_bases.transports.KnowledgeBasesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.KnowledgeBasesTransport() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1"} + pager = client.list_knowledge_bases(request=sample_request) -def test_knowledge_bases_auth_adc(): - # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, knowledge_base.KnowledgeBase) for i in results) + + pages = list(client.list_knowledge_bases(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + knowledge_base.GetKnowledgeBaseRequest, + dict, + ], +) +def test_get_knowledge_base_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = knowledge_base.KnowledgeBase( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_knowledge_base(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, knowledge_base.KnowledgeBase) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + + +def test_get_knowledge_base_rest_required_fields( + request_type=knowledge_base.GetKnowledgeBaseRequest, +): + transport_class = transports.KnowledgeBasesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = knowledge_base.KnowledgeBase() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_knowledge_base(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_knowledge_base_rest_unset_required_fields(): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_knowledge_base._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_knowledge_base_rest_interceptors(null_interceptor): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.KnowledgeBasesRestInterceptor(), + ) + client = KnowledgeBasesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "post_get_knowledge_base" + ) as post, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "pre_get_knowledge_base" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = knowledge_base.GetKnowledgeBaseRequest.pb( + knowledge_base.GetKnowledgeBaseRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = knowledge_base.KnowledgeBase.to_json( + knowledge_base.KnowledgeBase() + ) + + request = knowledge_base.GetKnowledgeBaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = knowledge_base.KnowledgeBase() + + client.get_knowledge_base( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_knowledge_base_rest_bad_request( + transport: str = "rest", request_type=knowledge_base.GetKnowledgeBaseRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_knowledge_base(request) + + +def test_get_knowledge_base_rest_flattened(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = knowledge_base.KnowledgeBase() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/knowledgeBases/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_knowledge_base(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/knowledgeBases/*}" % client.transport._host, args[1] + ) + + +def test_get_knowledge_base_rest_flattened_error(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_knowledge_base( + knowledge_base.GetKnowledgeBaseRequest(), + name="name_value", + ) + + +def test_get_knowledge_base_rest_error(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_knowledge_base.CreateKnowledgeBaseRequest, + dict, + ], +) +def test_create_knowledge_base_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["knowledge_base"] = { + "name": "name_value", + "display_name": "display_name_value", + "language_code": "language_code_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_knowledge_base(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_knowledge_base.KnowledgeBase) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + + +def test_create_knowledge_base_rest_required_fields( + request_type=gcd_knowledge_base.CreateKnowledgeBaseRequest, +): + transport_class = transports.KnowledgeBasesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_knowledge_base(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_knowledge_base_rest_unset_required_fields(): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_knowledge_base._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "knowledgeBase", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_knowledge_base_rest_interceptors(null_interceptor): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.KnowledgeBasesRestInterceptor(), + ) + client = KnowledgeBasesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "post_create_knowledge_base" + ) as post, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "pre_create_knowledge_base" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_knowledge_base.CreateKnowledgeBaseRequest.pb( + gcd_knowledge_base.CreateKnowledgeBaseRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_knowledge_base.KnowledgeBase.to_json( + gcd_knowledge_base.KnowledgeBase() + ) + + request = gcd_knowledge_base.CreateKnowledgeBaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_knowledge_base.KnowledgeBase() + + client.create_knowledge_base( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_knowledge_base_rest_bad_request( + transport: str = "rest", request_type=gcd_knowledge_base.CreateKnowledgeBaseRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["knowledge_base"] = { + "name": "name_value", + "display_name": "display_name_value", + "language_code": "language_code_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_knowledge_base(request) + + +def test_create_knowledge_base_rest_flattened(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + knowledge_base=gcd_knowledge_base.KnowledgeBase(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_knowledge_base(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*}/knowledgeBases" % client.transport._host, args[1] + ) + + +def test_create_knowledge_base_rest_flattened_error(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_knowledge_base( + gcd_knowledge_base.CreateKnowledgeBaseRequest(), + parent="parent_value", + knowledge_base=gcd_knowledge_base.KnowledgeBase(name="name_value"), + ) + + +def test_create_knowledge_base_rest_error(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + knowledge_base.DeleteKnowledgeBaseRequest, + dict, + ], +) +def test_delete_knowledge_base_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_knowledge_base(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_knowledge_base_rest_required_fields( + request_type=knowledge_base.DeleteKnowledgeBaseRequest, +): + transport_class = transports.KnowledgeBasesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_knowledge_base._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_knowledge_base(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_knowledge_base_rest_unset_required_fields(): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_knowledge_base._get_unset_required_fields({}) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_knowledge_base_rest_interceptors(null_interceptor): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.KnowledgeBasesRestInterceptor(), + ) + client = KnowledgeBasesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "pre_delete_knowledge_base" + ) as pre: + pre.assert_not_called() + pb_message = knowledge_base.DeleteKnowledgeBaseRequest.pb( + knowledge_base.DeleteKnowledgeBaseRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = knowledge_base.DeleteKnowledgeBaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_knowledge_base( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_knowledge_base_rest_bad_request( + transport: str = "rest", request_type=knowledge_base.DeleteKnowledgeBaseRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_knowledge_base(request) + + +def test_delete_knowledge_base_rest_flattened(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/knowledgeBases/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_knowledge_base(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/knowledgeBases/*}" % client.transport._host, args[1] + ) + + +def test_delete_knowledge_base_rest_flattened_error(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_knowledge_base( + knowledge_base.DeleteKnowledgeBaseRequest(), + name="name_value", + ) + + +def test_delete_knowledge_base_rest_error(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_knowledge_base.UpdateKnowledgeBaseRequest, + dict, + ], +) +def test_update_knowledge_base_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "knowledge_base": {"name": "projects/sample1/knowledgeBases/sample2"} + } + request_init["knowledge_base"] = { + "name": "projects/sample1/knowledgeBases/sample2", + "display_name": "display_name_value", + "language_code": "language_code_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_knowledge_base(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_knowledge_base.KnowledgeBase) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + + +def test_update_knowledge_base_rest_required_fields( + request_type=gcd_knowledge_base.UpdateKnowledgeBaseRequest, +): + transport_class = transports.KnowledgeBasesRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_knowledge_base._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_knowledge_base(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_knowledge_base_rest_unset_required_fields(): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_knowledge_base._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("knowledgeBase",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_knowledge_base_rest_interceptors(null_interceptor): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.KnowledgeBasesRestInterceptor(), + ) + client = KnowledgeBasesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "post_update_knowledge_base" + ) as post, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "pre_update_knowledge_base" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_knowledge_base.UpdateKnowledgeBaseRequest.pb( + gcd_knowledge_base.UpdateKnowledgeBaseRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_knowledge_base.KnowledgeBase.to_json( + gcd_knowledge_base.KnowledgeBase() + ) + + request = gcd_knowledge_base.UpdateKnowledgeBaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_knowledge_base.KnowledgeBase() + + client.update_knowledge_base( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_knowledge_base_rest_bad_request( + transport: str = "rest", request_type=gcd_knowledge_base.UpdateKnowledgeBaseRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "knowledge_base": {"name": "projects/sample1/knowledgeBases/sample2"} + } + request_init["knowledge_base"] = { + "name": "projects/sample1/knowledgeBases/sample2", + "display_name": "display_name_value", + "language_code": "language_code_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_knowledge_base(request) + + +def test_update_knowledge_base_rest_flattened(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase() + + # get arguments that satisfy an http rule for this method + sample_request = { + "knowledge_base": {"name": "projects/sample1/knowledgeBases/sample2"} + } + + # get truthy value for each flattened field + mock_args = dict( + knowledge_base=gcd_knowledge_base.KnowledgeBase(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_knowledge_base(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{knowledge_base.name=projects/*/knowledgeBases/*}" + % client.transport._host, + args[1], + ) + + +def test_update_knowledge_base_rest_flattened_error(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_knowledge_base( + gcd_knowledge_base.UpdateKnowledgeBaseRequest(), + knowledge_base=gcd_knowledge_base.KnowledgeBase(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_knowledge_base_rest_error(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = KnowledgeBasesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = KnowledgeBasesClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = KnowledgeBasesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = KnowledgeBasesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = KnowledgeBasesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.KnowledgeBasesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.KnowledgeBasesGrpcTransport, + transports.KnowledgeBasesGrpcAsyncIOTransport, + transports.KnowledgeBasesRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = KnowledgeBasesClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.KnowledgeBasesGrpcTransport, + ) + + +def test_knowledge_bases_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.KnowledgeBasesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_knowledge_bases_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.knowledge_bases.transports.KnowledgeBasesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.KnowledgeBasesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_knowledge_bases", + "get_knowledge_base", + "create_knowledge_base", + "delete_knowledge_base", + "update_knowledge_base", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_knowledge_bases_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.dialogflow_v2.services.knowledge_bases.transports.KnowledgeBasesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.KnowledgeBasesTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_knowledge_bases_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.dialogflow_v2.services.knowledge_bases.transports.KnowledgeBasesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.KnowledgeBasesTransport() + adc.assert_called_once() + + +def test_knowledge_bases_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: adc.return_value = (ga_credentials.AnonymousCredentials(), None) KnowledgeBasesClient() adc.assert_called_once_with( @@ -2391,6 +3857,7 @@ def test_knowledge_bases_transport_auth_adc(transport_class): [ transports.KnowledgeBasesGrpcTransport, transports.KnowledgeBasesGrpcAsyncIOTransport, + transports.KnowledgeBasesRestTransport, ], ) def test_knowledge_bases_transport_auth_gdch_credentials(transport_class): @@ -2491,11 +3958,23 @@ def test_knowledge_bases_grpc_transport_client_cert_source_for_mtls(transport_cl ) +def test_knowledge_bases_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.KnowledgeBasesRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_knowledge_bases_host_no_port(transport_name): @@ -2506,7 +3985,11 @@ def test_knowledge_bases_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2514,6 +3997,7 @@ def test_knowledge_bases_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_knowledge_bases_host_with_port(transport_name): @@ -2524,7 +4008,45 @@ def test_knowledge_bases_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_knowledge_bases_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = KnowledgeBasesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = KnowledgeBasesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_knowledge_bases._session + session2 = client2.transport.list_knowledge_bases._session + assert session1 != session2 + session1 = client1.transport.get_knowledge_base._session + session2 = client2.transport.get_knowledge_base._session + assert session1 != session2 + session1 = client1.transport.create_knowledge_base._session + session2 = client2.transport.create_knowledge_base._session + assert session1 != session2 + session1 = client1.transport.delete_knowledge_base._session + session2 = client2.transport.delete_knowledge_base._session + assert session1 != session2 + session1 = client1.transport.update_knowledge_base._session + session2 = client2.transport.update_knowledge_base._session + assert session1 != session2 def test_knowledge_bases_grpc_transport_channel(): @@ -2816,6 +4338,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = KnowledgeBasesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3535,6 +5343,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3552,6 +5361,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_participants.py b/tests/unit/gapic/dialogflow_v2/test_participants.py index 656cd3089..f8151833c 100644 --- a/tests/unit/gapic/dialogflow_v2/test_participants.py +++ b/tests/unit/gapic/dialogflow_v2/test_participants.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,6 +36,7 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore from google.type import latlng_pb2 # type: ignore import grpc @@ -41,6 +44,8 @@ from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.participants import ( ParticipantsAsyncClient, @@ -100,6 +105,7 @@ def test__get_default_mtls_endpoint(): [ (ParticipantsClient, "grpc"), (ParticipantsAsyncClient, "grpc_asyncio"), + (ParticipantsClient, "rest"), ], ) def test_participants_client_from_service_account_info(client_class, transport_name): @@ -113,7 +119,11 @@ def test_participants_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -121,6 +131,7 @@ def test_participants_client_from_service_account_info(client_class, transport_n [ (transports.ParticipantsGrpcTransport, "grpc"), (transports.ParticipantsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ParticipantsRestTransport, "rest"), ], ) def test_participants_client_service_account_always_use_jwt( @@ -146,6 +157,7 @@ def test_participants_client_service_account_always_use_jwt( [ (ParticipantsClient, "grpc"), (ParticipantsAsyncClient, "grpc_asyncio"), + (ParticipantsClient, "rest"), ], ) def test_participants_client_from_service_account_file(client_class, transport_name): @@ -166,13 +178,18 @@ def test_participants_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_participants_client_get_transport_class(): transport = ParticipantsClient.get_transport_class() available_transports = [ transports.ParticipantsGrpcTransport, + transports.ParticipantsRestTransport, ] assert transport in available_transports @@ -189,6 +206,7 @@ def test_participants_client_get_transport_class(): transports.ParticipantsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ParticipantsClient, transports.ParticipantsRestTransport, "rest"), ], ) @mock.patch.object( @@ -332,6 +350,8 @@ def test_participants_client_client_options( "grpc_asyncio", "false", ), + (ParticipantsClient, transports.ParticipantsRestTransport, "rest", "true"), + (ParticipantsClient, transports.ParticipantsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -525,6 +545,7 @@ def test_participants_client_get_mtls_endpoint_and_cert_source(client_class): transports.ParticipantsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ParticipantsClient, transports.ParticipantsRestTransport, "rest"), ], ) def test_participants_client_client_options_scopes( @@ -565,6 +586,7 @@ def test_participants_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (ParticipantsClient, transports.ParticipantsRestTransport, "rest", None), ], ) def test_participants_client_client_options_credentials_file( @@ -2957,178 +2979,2539 @@ async def test_suggest_smart_replies_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ParticipantsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + gcd_participant.CreateParticipantRequest, + dict, + ], +) +def test_create_participant_rest(request_type): + client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ParticipantsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request_init["participant"] = { + "name": "name_value", + "role": 1, + "sip_recording_media_label": "sip_recording_media_label_value", + "obfuscated_external_user_id": "obfuscated_external_user_id_value", + "documents_metadata_filters": {}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant( + name="name_value", + role=gcd_participant.Participant.Role.HUMAN_AGENT, + sip_recording_media_label="sip_recording_media_label_value", + obfuscated_external_user_id="obfuscated_external_user_id_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ParticipantsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = ParticipantsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_participant(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_participant.Participant) + assert response.name == "name_value" + assert response.role == gcd_participant.Participant.Role.HUMAN_AGENT + assert response.sip_recording_media_label == "sip_recording_media_label_value" + assert response.obfuscated_external_user_id == "obfuscated_external_user_id_value" + + +def test_create_participant_rest_required_fields( + request_type=gcd_participant.CreateParticipantRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.ParticipantsGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_participant._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_participant._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_participant(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_participant_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ParticipantsClient( - client_options=options, - transport=transport, - ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ParticipantsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + unset_fields = transport.create_participant._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "participant", + ) ) + ) - # It is an error to provide scopes and a transport instance. - transport = transports.ParticipantsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_participant_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), ) - with pytest.raises(ValueError): - client = ParticipantsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_create_participant" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_create_participant" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_participant.CreateParticipantRequest.pb( + gcd_participant.CreateParticipantRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_participant.Participant.to_json( + gcd_participant.Participant() ) + request = gcd_participant.CreateParticipantRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_participant.Participant() -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ParticipantsGrpcTransport( + client.create_participant( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_participant_rest_bad_request( + transport: str = "rest", request_type=gcd_participant.CreateParticipantRequest +): + client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = ParticipantsClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request_init["participant"] = { + "name": "name_value", + "role": 1, + "sip_recording_media_label": "sip_recording_media_label_value", + "obfuscated_external_user_id": "obfuscated_external_user_id_value", + "documents_metadata_filters": {}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_participant(request) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ParticipantsGrpcTransport( + +def test_create_participant_rest_flattened(): + client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.ParticipantsGrpcAsyncIOTransport( + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + participant=gcd_participant.Participant(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_participant(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/conversations/*}/participants" + % client.transport._host, + args[1], + ) + + +def test_create_participant_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_participant( + gcd_participant.CreateParticipantRequest(), + parent="parent_value", + participant=gcd_participant.Participant(name="name_value"), + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.ParticipantsGrpcTransport, - transports.ParticipantsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + +def test_create_participant_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + participant.GetParticipantRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = ParticipantsClient.get_transport_class(transport_name)( +def test_get_participant_rest(request_type): + client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.Participant( + name="name_value", + role=participant.Participant.Role.HUMAN_AGENT, + sip_recording_media_label="sip_recording_media_label_value", + obfuscated_external_user_id="obfuscated_external_user_id_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_participant(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, participant.Participant) + assert response.name == "name_value" + assert response.role == participant.Participant.Role.HUMAN_AGENT + assert response.sip_recording_media_label == "sip_recording_media_label_value" + assert response.obfuscated_external_user_id == "obfuscated_external_user_id_value" + + +def test_get_participant_rest_required_fields( + request_type=participant.GetParticipantRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_participant._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_participant._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.ParticipantsGrpcTransport, - ) + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = participant.Participant() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + response_value = Response() + response_value.status_code = 200 -def test_participants_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ParticipantsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) + pb_return_value = participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value -def test_participants_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.participants.transports.ParticipantsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ParticipantsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response = client.get_participant(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "create_participant", - "get_participant", - "list_participants", - "update_participant", - "analyze_content", - "streaming_analyze_content", - "suggest_articles", - "suggest_faq_answers", - "suggest_smart_replies", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params - with pytest.raises(NotImplementedError): - transport.close() - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() +def test_get_participant_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + unset_fields = transport.get_participant._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) -def test_participants_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_participant_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_get_participant" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_get_participant" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.GetParticipantRequest.pb( + participant.GetParticipantRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.Participant.to_json( + participant.Participant() + ) + + request = participant.GetParticipantRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.Participant() + + client.get_participant( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_participant_rest_bad_request( + transport: str = "rest", request_type=participant.GetParticipantRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_participant(request) + + +def test_get_participant_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.Participant() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_participant(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/conversations/*/participants/*}" + % client.transport._host, + args[1], + ) + + +def test_get_participant_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_participant( + participant.GetParticipantRequest(), + name="name_value", + ) + + +def test_get_participant_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + participant.ListParticipantsRequest, + dict, + ], +) +def test_list_participants_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.ListParticipantsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.ListParticipantsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_participants(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListParticipantsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_participants_rest_required_fields( + request_type=participant.ListParticipantsRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_participants._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_participants._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = participant.ListParticipantsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = participant.ListParticipantsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_participants(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_participants_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_participants._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_participants_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_list_participants" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_list_participants" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.ListParticipantsRequest.pb( + participant.ListParticipantsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.ListParticipantsResponse.to_json( + participant.ListParticipantsResponse() + ) + + request = participant.ListParticipantsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.ListParticipantsResponse() + + client.list_participants( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_participants_rest_bad_request( + transport: str = "rest", request_type=participant.ListParticipantsRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_participants(request) + + +def test_list_participants_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.ListParticipantsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.ListParticipantsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_participants(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/conversations/*}/participants" + % client.transport._host, + args[1], + ) + + +def test_list_participants_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_participants( + participant.ListParticipantsRequest(), + parent="parent_value", + ) + + +def test_list_participants_rest_pager(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + participant.ListParticipantsResponse( + participants=[ + participant.Participant(), + participant.Participant(), + participant.Participant(), + ], + next_page_token="abc", + ), + participant.ListParticipantsResponse( + participants=[], + next_page_token="def", + ), + participant.ListParticipantsResponse( + participants=[ + participant.Participant(), + ], + next_page_token="ghi", + ), + participant.ListParticipantsResponse( + participants=[ + participant.Participant(), + participant.Participant(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + participant.ListParticipantsResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/conversations/sample2"} + + pager = client.list_participants(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, participant.Participant) for i in results) + + pages = list(client.list_participants(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_participant.UpdateParticipantRequest, + dict, + ], +) +def test_update_participant_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "participant": { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + } + request_init["participant"] = { + "name": "projects/sample1/conversations/sample2/participants/sample3", + "role": 1, + "sip_recording_media_label": "sip_recording_media_label_value", + "obfuscated_external_user_id": "obfuscated_external_user_id_value", + "documents_metadata_filters": {}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant( + name="name_value", + role=gcd_participant.Participant.Role.HUMAN_AGENT, + sip_recording_media_label="sip_recording_media_label_value", + obfuscated_external_user_id="obfuscated_external_user_id_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_participant(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_participant.Participant) + assert response.name == "name_value" + assert response.role == gcd_participant.Participant.Role.HUMAN_AGENT + assert response.sip_recording_media_label == "sip_recording_media_label_value" + assert response.obfuscated_external_user_id == "obfuscated_external_user_id_value" + + +def test_update_participant_rest_required_fields( + request_type=gcd_participant.UpdateParticipantRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_participant._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_participant._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_participant(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_participant_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_participant._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "participant", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_participant_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_update_participant" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_update_participant" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_participant.UpdateParticipantRequest.pb( + gcd_participant.UpdateParticipantRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_participant.Participant.to_json( + gcd_participant.Participant() + ) + + request = gcd_participant.UpdateParticipantRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_participant.Participant() + + client.update_participant( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_participant_rest_bad_request( + transport: str = "rest", request_type=gcd_participant.UpdateParticipantRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "participant": { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + } + request_init["participant"] = { + "name": "projects/sample1/conversations/sample2/participants/sample3", + "role": 1, + "sip_recording_media_label": "sip_recording_media_label_value", + "obfuscated_external_user_id": "obfuscated_external_user_id_value", + "documents_metadata_filters": {}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_participant(request) + + +def test_update_participant_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant() + + # get arguments that satisfy an http rule for this method + sample_request = { + "participant": { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + } + + # get truthy value for each flattened field + mock_args = dict( + participant=gcd_participant.Participant(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_participant(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{participant.name=projects/*/conversations/*/participants/*}" + % client.transport._host, + args[1], + ) + + +def test_update_participant_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_participant( + gcd_participant.UpdateParticipantRequest(), + participant=gcd_participant.Participant(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_participant_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_participant.AnalyzeContentRequest, + dict, + ], +) +def test_analyze_content_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "participant": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.AnalyzeContentResponse( + reply_text="reply_text_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.AnalyzeContentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.analyze_content(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_participant.AnalyzeContentResponse) + assert response.reply_text == "reply_text_value" + + +def test_analyze_content_rest_required_fields( + request_type=gcd_participant.AnalyzeContentRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["participant"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_content._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["participant"] = "participant_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_content._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "participant" in jsonified_request + assert jsonified_request["participant"] == "participant_value" + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_participant.AnalyzeContentResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_participant.AnalyzeContentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.analyze_content(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_analyze_content_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.analyze_content._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("participant",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_analyze_content_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_analyze_content" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_analyze_content" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_participant.AnalyzeContentRequest.pb( + gcd_participant.AnalyzeContentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_participant.AnalyzeContentResponse.to_json( + gcd_participant.AnalyzeContentResponse() + ) + + request = gcd_participant.AnalyzeContentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_participant.AnalyzeContentResponse() + + client.analyze_content( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_analyze_content_rest_bad_request( + transport: str = "rest", request_type=gcd_participant.AnalyzeContentRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "participant": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.analyze_content(request) + + +def test_analyze_content_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.AnalyzeContentResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "participant": "projects/sample1/conversations/sample2/participants/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + participant="participant_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.AnalyzeContentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.analyze_content(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{participant=projects/*/conversations/*/participants/*}:analyzeContent" + % client.transport._host, + args[1], + ) + + +def test_analyze_content_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.analyze_content( + gcd_participant.AnalyzeContentRequest(), + participant="participant_value", + text_input=session.TextInput(text="text_value"), + event_input=session.EventInput(name="name_value"), + ) + + +def test_analyze_content_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_streaming_analyze_content_rest_no_http_options(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = participant.StreamingAnalyzeContentRequest() + requests = [request] + with pytest.raises(RuntimeError): + client.streaming_analyze_content(requests) + + +@pytest.mark.parametrize( + "request_type", + [ + participant.SuggestArticlesRequest, + dict, + ], +) +def test_suggest_articles_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestArticlesResponse( + latest_message="latest_message_value", + context_size=1311, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestArticlesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.suggest_articles(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, participant.SuggestArticlesResponse) + assert response.latest_message == "latest_message_value" + assert response.context_size == 1311 + + +def test_suggest_articles_rest_required_fields( + request_type=participant.SuggestArticlesRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_articles._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_articles._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = participant.SuggestArticlesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = participant.SuggestArticlesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.suggest_articles(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_suggest_articles_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.suggest_articles._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_suggest_articles_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_suggest_articles" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_suggest_articles" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.SuggestArticlesRequest.pb( + participant.SuggestArticlesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.SuggestArticlesResponse.to_json( + participant.SuggestArticlesResponse() + ) + + request = participant.SuggestArticlesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.SuggestArticlesResponse() + + client.suggest_articles( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_suggest_articles_rest_bad_request( + transport: str = "rest", request_type=participant.SuggestArticlesRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.suggest_articles(request) + + +def test_suggest_articles_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestArticlesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestArticlesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.suggest_articles(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestArticles" + % client.transport._host, + args[1], + ) + + +def test_suggest_articles_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.suggest_articles( + participant.SuggestArticlesRequest(), + parent="parent_value", + ) + + +def test_suggest_articles_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + participant.SuggestFaqAnswersRequest, + dict, + ], +) +def test_suggest_faq_answers_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestFaqAnswersResponse( + latest_message="latest_message_value", + context_size=1311, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestFaqAnswersResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.suggest_faq_answers(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, participant.SuggestFaqAnswersResponse) + assert response.latest_message == "latest_message_value" + assert response.context_size == 1311 + + +def test_suggest_faq_answers_rest_required_fields( + request_type=participant.SuggestFaqAnswersRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_faq_answers._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_faq_answers._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = participant.SuggestFaqAnswersResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = participant.SuggestFaqAnswersResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.suggest_faq_answers(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_suggest_faq_answers_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.suggest_faq_answers._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_suggest_faq_answers_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_suggest_faq_answers" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_suggest_faq_answers" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.SuggestFaqAnswersRequest.pb( + participant.SuggestFaqAnswersRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.SuggestFaqAnswersResponse.to_json( + participant.SuggestFaqAnswersResponse() + ) + + request = participant.SuggestFaqAnswersRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.SuggestFaqAnswersResponse() + + client.suggest_faq_answers( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_suggest_faq_answers_rest_bad_request( + transport: str = "rest", request_type=participant.SuggestFaqAnswersRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.suggest_faq_answers(request) + + +def test_suggest_faq_answers_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestFaqAnswersResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestFaqAnswersResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.suggest_faq_answers(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestFaqAnswers" + % client.transport._host, + args[1], + ) + + +def test_suggest_faq_answers_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.suggest_faq_answers( + participant.SuggestFaqAnswersRequest(), + parent="parent_value", + ) + + +def test_suggest_faq_answers_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + participant.SuggestSmartRepliesRequest, + dict, + ], +) +def test_suggest_smart_replies_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestSmartRepliesResponse( + latest_message="latest_message_value", + context_size=1311, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestSmartRepliesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.suggest_smart_replies(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, participant.SuggestSmartRepliesResponse) + assert response.latest_message == "latest_message_value" + assert response.context_size == 1311 + + +def test_suggest_smart_replies_rest_required_fields( + request_type=participant.SuggestSmartRepliesRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_smart_replies._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_smart_replies._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = participant.SuggestSmartRepliesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = participant.SuggestSmartRepliesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.suggest_smart_replies(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_suggest_smart_replies_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.suggest_smart_replies._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_suggest_smart_replies_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_suggest_smart_replies" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_suggest_smart_replies" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.SuggestSmartRepliesRequest.pb( + participant.SuggestSmartRepliesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.SuggestSmartRepliesResponse.to_json( + participant.SuggestSmartRepliesResponse() + ) + + request = participant.SuggestSmartRepliesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.SuggestSmartRepliesResponse() + + client.suggest_smart_replies( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_suggest_smart_replies_rest_bad_request( + transport: str = "rest", request_type=participant.SuggestSmartRepliesRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.suggest_smart_replies(request) + + +def test_suggest_smart_replies_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestSmartRepliesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestSmartRepliesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.suggest_smart_replies(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestSmartReplies" + % client.transport._host, + args[1], + ) + + +def test_suggest_smart_replies_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.suggest_smart_replies( + participant.SuggestSmartRepliesRequest(), + parent="parent_value", + ) + + +def test_suggest_smart_replies_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_streaming_analyze_content_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + # Since a `google.api.http` annotation is required for using a rest transport + # method, this should error. + with pytest.raises(NotImplementedError) as not_implemented_error: + client.streaming_analyze_content({}) + assert "Method StreamingAnalyzeContent is not available over REST transport" in str( + not_implemented_error.value + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ParticipantsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ParticipantsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ParticipantsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ParticipantsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ParticipantsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ParticipantsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ParticipantsGrpcTransport, + transports.ParticipantsGrpcAsyncIOTransport, + transports.ParticipantsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = ParticipantsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ParticipantsGrpcTransport, + ) + + +def test_participants_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ParticipantsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_participants_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.participants.transports.ParticipantsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ParticipantsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "create_participant", + "get_participant", + "list_participants", + "update_participant", + "analyze_content", + "streaming_analyze_content", + "suggest_articles", + "suggest_faq_answers", + "suggest_smart_replies", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_participants_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True ) as load_creds, mock.patch( "google.cloud.dialogflow_v2.services.participants.transports.ParticipantsTransport._prep_wrapped_messages" ) as Transport: @@ -3203,6 +5586,7 @@ def test_participants_transport_auth_adc(transport_class): [ transports.ParticipantsGrpcTransport, transports.ParticipantsGrpcAsyncIOTransport, + transports.ParticipantsRestTransport, ], ) def test_participants_transport_auth_gdch_credentials(transport_class): @@ -3300,11 +5684,23 @@ def test_participants_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_participants_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.ParticipantsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_participants_host_no_port(transport_name): @@ -3315,7 +5711,11 @@ def test_participants_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3323,6 +5723,7 @@ def test_participants_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_participants_host_with_port(transport_name): @@ -3333,7 +5734,57 @@ def test_participants_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_participants_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ParticipantsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ParticipantsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_participant._session + session2 = client2.transport.create_participant._session + assert session1 != session2 + session1 = client1.transport.get_participant._session + session2 = client2.transport.get_participant._session + assert session1 != session2 + session1 = client1.transport.list_participants._session + session2 = client2.transport.list_participants._session + assert session1 != session2 + session1 = client1.transport.update_participant._session + session2 = client2.transport.update_participant._session + assert session1 != session2 + session1 = client1.transport.analyze_content._session + session2 = client2.transport.analyze_content._session + assert session1 != session2 + session1 = client1.transport.streaming_analyze_content._session + session2 = client2.transport.streaming_analyze_content._session + assert session1 != session2 + session1 = client1.transport.suggest_articles._session + session2 = client2.transport.suggest_articles._session + assert session1 != session2 + session1 = client1.transport.suggest_faq_answers._session + session2 = client2.transport.suggest_faq_answers._session + assert session1 != session2 + session1 = client1.transport.suggest_smart_replies._session + session2 = client2.transport.suggest_smart_replies._session + assert session1 != session2 def test_participants_grpc_transport_channel(): @@ -3748,6 +6199,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4465,6 +7202,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4482,6 +7220,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_session_entity_types.py b/tests/unit/gapic/dialogflow_v2/test_session_entity_types.py index 7867f97d3..9e8972ec6 100644 --- a/tests/unit/gapic/dialogflow_v2/test_session_entity_types.py +++ b/tests/unit/gapic/dialogflow_v2/test_session_entity_types.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,11 +36,14 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.session_entity_types import ( SessionEntityTypesAsyncClient, @@ -103,6 +108,7 @@ def test__get_default_mtls_endpoint(): [ (SessionEntityTypesClient, "grpc"), (SessionEntityTypesAsyncClient, "grpc_asyncio"), + (SessionEntityTypesClient, "rest"), ], ) def test_session_entity_types_client_from_service_account_info( @@ -118,7 +124,11 @@ def test_session_entity_types_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -126,6 +136,7 @@ def test_session_entity_types_client_from_service_account_info( [ (transports.SessionEntityTypesGrpcTransport, "grpc"), (transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.SessionEntityTypesRestTransport, "rest"), ], ) def test_session_entity_types_client_service_account_always_use_jwt( @@ -151,6 +162,7 @@ def test_session_entity_types_client_service_account_always_use_jwt( [ (SessionEntityTypesClient, "grpc"), (SessionEntityTypesAsyncClient, "grpc_asyncio"), + (SessionEntityTypesClient, "rest"), ], ) def test_session_entity_types_client_from_service_account_file( @@ -173,13 +185,18 @@ def test_session_entity_types_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_session_entity_types_client_get_transport_class(): transport = SessionEntityTypesClient.get_transport_class() available_transports = [ transports.SessionEntityTypesGrpcTransport, + transports.SessionEntityTypesRestTransport, ] assert transport in available_transports @@ -196,6 +213,7 @@ def test_session_entity_types_client_get_transport_class(): transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (SessionEntityTypesClient, transports.SessionEntityTypesRestTransport, "rest"), ], ) @mock.patch.object( @@ -351,6 +369,18 @@ def test_session_entity_types_client_client_options( "grpc_asyncio", "false", ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + "true", + ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -550,6 +580,7 @@ def test_session_entity_types_client_get_mtls_endpoint_and_cert_source(client_cl transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (SessionEntityTypesClient, transports.SessionEntityTypesRestTransport, "rest"), ], ) def test_session_entity_types_client_client_options_scopes( @@ -590,6 +621,12 @@ def test_session_entity_types_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + None, + ), ], ) def test_session_entity_types_client_client_options_credentials_file( @@ -2194,224 +2231,1725 @@ async def test_delete_session_entity_type_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + session_entity_type.ListSessionEntityTypesRequest, + dict, + ], +) +def test_list_session_entity_types_rest(request_type): + client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options=options, - transport=transport, + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = session_entity_type.ListSessionEntityTypesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.pb( + return_value ) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_session_entity_types(request) + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListSessionEntityTypesPager) + assert response.next_page_token == "next_page_token_value" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + +def test_list_session_entity_types_rest_required_fields( + request_type=session_entity_type.ListSessionEntityTypesRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - client = SessionEntityTypesClient(transport=transport) - assert client.transport is transport + # verify fields with default values are dropped -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_session_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_session_entity_types._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) ) - channel = transport.grpc_channel - assert channel + jsonified_request.update(unset_fields) - transport = transports.SessionEntityTypesGrpcAsyncIOTransport( + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session_entity_type.ListSessionEntityTypesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + response_value = Response() + response_value.status_code = 200 -@pytest.mark.parametrize( - "transport_class", - [ - transports.SessionEntityTypesGrpcTransport, - transports.SessionEntityTypesGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = SessionEntityTypesClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name + response = client.list_session_entity_types(request) + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. - client = SessionEntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), + +def test_list_session_entity_types_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.SessionEntityTypesGrpcTransport, + + unset_fields = transport.list_session_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) ) -def test_session_entity_types_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.SessionEntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_session_entity_types_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "post_list_session_entity_types" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_list_session_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session_entity_type.ListSessionEntityTypesRequest.pb( + session_entity_type.ListSessionEntityTypesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + session_entity_type.ListSessionEntityTypesResponse.to_json( + session_entity_type.ListSessionEntityTypesResponse() + ) ) + request = session_entity_type.ListSessionEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session_entity_type.ListSessionEntityTypesResponse() -def test_session_entity_types_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.session_entity_types.transports.SessionEntityTypesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.SessionEntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_session_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_session_entity_types", - "get_session_entity_type", - "create_session_entity_type", - "update_session_entity_type", - "delete_session_entity_type", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + pre.assert_called_once() + post.assert_called_once() + + +def test_list_session_entity_types_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.ListSessionEntityTypesRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_session_entity_types(request) -def test_session_entity_types_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.dialogflow_v2.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.SessionEntityTypesTransport( - credentials_file="credentials.json", - quota_project_id="octopus", +def test_list_session_entity_types_rest_flattened(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = session_entity_type.ListSessionEntityTypesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.pb( + return_value ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + client.list_session_entity_types(**mock_args) -def test_session_entity_types_base_transport_with_adc(): - # Test the default credentials are used if credentials and credentials_file are None. - with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( - "google.cloud.dialogflow_v2.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.SessionEntityTypesTransport() - adc.assert_called_once() + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent/sessions/*}/entityTypes" + % client.transport._host, + args[1], + ) -def test_session_entity_types_auth_adc(): - # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - SessionEntityTypesClient() - adc.assert_called_once_with( - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id=None, +def test_list_session_entity_types_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_session_entity_types( + session_entity_type.ListSessionEntityTypesRequest(), + parent="parent_value", ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.SessionEntityTypesGrpcTransport, +def test_list_session_entity_types_rest_pager(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + ], + next_page_token="abc", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[], + next_page_token="def", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + ], + next_page_token="ghi", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + session_entity_type.ListSessionEntityTypesResponse.to_json(x) + for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + pager = client.list_session_entity_types(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all( + isinstance(i, session_entity_type.SessionEntityType) for i in results + ) + + pages = list(client.list_session_entity_types(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + session_entity_type.GetSessionEntityTypeRequest, + dict, + ], +) +def test_get_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_get_session_entity_type_rest_required_fields( + request_type=session_entity_type.GetSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session_entity_type.SessionEntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "post_get_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_get_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session_entity_type.GetSessionEntityTypeRequest.pb( + session_entity_type.GetSessionEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = session_entity_type.SessionEntityType.to_json( + session_entity_type.SessionEntityType() + ) + + request = session_entity_type.GetSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session_entity_type.SessionEntityType() + + client.get_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.GetSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_session_entity_type(request) + + +def test_get_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_session_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/agent/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_get_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_session_entity_type( + session_entity_type.GetSessionEntityTypeRequest(), + name="name_value", + ) + + +def test_get_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_session_entity_type.CreateSessionEntityTypeRequest, + dict, + ], +) +def test_create_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request_init["session_entity_type"] = { + "name": "name_value", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=gcd_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == gcd_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_create_session_entity_type_rest_required_fields( + request_type=gcd_session_entity_type.CreateSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "sessionEntityType", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "post_create_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_create_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_session_entity_type.CreateSessionEntityTypeRequest.pb( + gcd_session_entity_type.CreateSessionEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_session_entity_type.SessionEntityType.to_json( + gcd_session_entity_type.SessionEntityType() + ) + + request = gcd_session_entity_type.CreateSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_session_entity_type.SessionEntityType() + + client.create_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=gcd_session_entity_type.CreateSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request_init["session_entity_type"] = { + "name": "name_value", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_session_entity_type(request) + + +def test_create_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + session_entity_type=gcd_session_entity_type.SessionEntityType( + name="name_value" + ), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_session_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent/sessions/*}/entityTypes" + % client.transport._host, + args[1], + ) + + +def test_create_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_session_entity_type( + gcd_session_entity_type.CreateSessionEntityTypeRequest(), + parent="parent_value", + session_entity_type=gcd_session_entity_type.SessionEntityType( + name="name_value" + ), + ) + + +def test_create_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_session_entity_type.UpdateSessionEntityTypeRequest, + dict, + ], +) +def test_update_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "session_entity_type": { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + } + request_init["session_entity_type"] = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=gcd_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == gcd_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_update_session_entity_type_rest_required_fields( + request_type=gcd_session_entity_type.UpdateSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_session_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("sessionEntityType",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "post_update_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_update_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_session_entity_type.UpdateSessionEntityTypeRequest.pb( + gcd_session_entity_type.UpdateSessionEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_session_entity_type.SessionEntityType.to_json( + gcd_session_entity_type.SessionEntityType() + ) + + request = gcd_session_entity_type.UpdateSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_session_entity_type.SessionEntityType() + + client.update_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=gcd_session_entity_type.UpdateSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "session_entity_type": { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + } + request_init["session_entity_type"] = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_session_entity_type(request) + + +def test_update_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "session_entity_type": { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + } + + # get truthy value for each flattened field + mock_args = dict( + session_entity_type=gcd_session_entity_type.SessionEntityType( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_session_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{session_entity_type.name=projects/*/agent/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_update_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_session_entity_type( + gcd_session_entity_type.UpdateSessionEntityTypeRequest(), + session_entity_type=gcd_session_entity_type.SessionEntityType( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + session_entity_type.DeleteSessionEntityTypeRequest, + dict, + ], +) +def test_delete_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_session_entity_type_rest_required_fields( + request_type=session_entity_type.DeleteSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_delete_session_entity_type" + ) as pre: + pre.assert_not_called() + pb_message = session_entity_type.DeleteSessionEntityTypeRequest.pb( + session_entity_type.DeleteSessionEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = session_entity_type.DeleteSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.DeleteSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_session_entity_type(request) + + +def test_delete_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_session_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/agent/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_session_entity_type( + session_entity_type.DeleteSessionEntityTypeRequest(), + name="name_value", + ) + + +def test_delete_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = SessionEntityTypesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.SessionEntityTypesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.SessionEntityTypesGrpcTransport, + transports.SessionEntityTypesGrpcAsyncIOTransport, + transports.SessionEntityTypesRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = SessionEntityTypesClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.SessionEntityTypesGrpcTransport, + ) + + +def test_session_entity_types_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.SessionEntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_session_entity_types_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.session_entity_types.transports.SessionEntityTypesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.SessionEntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_session_entity_types", + "get_session_entity_type", + "create_session_entity_type", + "update_session_entity_type", + "delete_session_entity_type", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_session_entity_types_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.dialogflow_v2.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.SessionEntityTypesTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_session_entity_types_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.dialogflow_v2.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.SessionEntityTypesTransport() + adc.assert_called_once() + + +def test_session_entity_types_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + SessionEntityTypesClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.SessionEntityTypesGrpcTransport, transports.SessionEntityTypesGrpcAsyncIOTransport, ], ) @@ -2436,6 +3974,7 @@ def test_session_entity_types_transport_auth_adc(transport_class): [ transports.SessionEntityTypesGrpcTransport, transports.SessionEntityTypesGrpcAsyncIOTransport, + transports.SessionEntityTypesRestTransport, ], ) def test_session_entity_types_transport_auth_gdch_credentials(transport_class): @@ -2538,11 +4077,23 @@ def test_session_entity_types_grpc_transport_client_cert_source_for_mtls( ) +def test_session_entity_types_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.SessionEntityTypesRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_session_entity_types_host_no_port(transport_name): @@ -2553,7 +4104,11 @@ def test_session_entity_types_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2561,6 +4116,7 @@ def test_session_entity_types_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_session_entity_types_host_with_port(transport_name): @@ -2571,7 +4127,45 @@ def test_session_entity_types_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_session_entity_types_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = SessionEntityTypesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = SessionEntityTypesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_session_entity_types._session + session2 = client2.transport.list_session_entity_types._session + assert session1 != session2 + session1 = client1.transport.get_session_entity_type._session + session2 = client2.transport.get_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.create_session_entity_type._session + session2 = client2.transport.create_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.update_session_entity_type._session + session2 = client2.transport.update_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.delete_session_entity_type._session + session2 = client2.transport.delete_session_entity_type._session + assert session1 != session2 def test_session_entity_types_grpc_transport_channel(): @@ -2870,6 +4464,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3589,6 +5469,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3606,6 +5487,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_sessions.py b/tests/unit/gapic/dialogflow_v2/test_sessions.py index 81a71c2f0..e268cf5cb 100644 --- a/tests/unit/gapic/dialogflow_v2/test_sessions.py +++ b/tests/unit/gapic/dialogflow_v2/test_sessions.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,6 +36,7 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore from google.rpc import status_pb2 # type: ignore from google.type import latlng_pb2 # type: ignore @@ -42,6 +45,8 @@ from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.sessions import ( SessionsAsyncClient, @@ -98,6 +103,7 @@ def test__get_default_mtls_endpoint(): [ (SessionsClient, "grpc"), (SessionsAsyncClient, "grpc_asyncio"), + (SessionsClient, "rest"), ], ) def test_sessions_client_from_service_account_info(client_class, transport_name): @@ -111,7 +117,11 @@ def test_sessions_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -119,6 +129,7 @@ def test_sessions_client_from_service_account_info(client_class, transport_name) [ (transports.SessionsGrpcTransport, "grpc"), (transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.SessionsRestTransport, "rest"), ], ) def test_sessions_client_service_account_always_use_jwt( @@ -144,6 +155,7 @@ def test_sessions_client_service_account_always_use_jwt( [ (SessionsClient, "grpc"), (SessionsAsyncClient, "grpc_asyncio"), + (SessionsClient, "rest"), ], ) def test_sessions_client_from_service_account_file(client_class, transport_name): @@ -164,13 +176,18 @@ def test_sessions_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_sessions_client_get_transport_class(): transport = SessionsClient.get_transport_class() available_transports = [ transports.SessionsGrpcTransport, + transports.SessionsRestTransport, ] assert transport in available_transports @@ -183,6 +200,7 @@ def test_sessions_client_get_transport_class(): [ (SessionsClient, transports.SessionsGrpcTransport, "grpc"), (SessionsAsyncClient, transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (SessionsClient, transports.SessionsRestTransport, "rest"), ], ) @mock.patch.object( @@ -324,6 +342,8 @@ def test_sessions_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (SessionsClient, transports.SessionsRestTransport, "rest", "true"), + (SessionsClient, transports.SessionsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -513,6 +533,7 @@ def test_sessions_client_get_mtls_endpoint_and_cert_source(client_class): [ (SessionsClient, transports.SessionsGrpcTransport, "grpc"), (SessionsAsyncClient, transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (SessionsClient, transports.SessionsRestTransport, "rest"), ], ) def test_sessions_client_client_options_scopes( @@ -548,6 +569,7 @@ def test_sessions_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (SessionsClient, transports.SessionsRestTransport, "rest", None), ], ) def test_sessions_client_client_options_credentials_file( @@ -1002,6 +1024,317 @@ async def test_streaming_detect_intent_async_from_dict(): await test_streaming_detect_intent_async(request_type=dict) +@pytest.mark.parametrize( + "request_type", + [ + gcd_session.DetectIntentRequest, + dict, + ], +) +def test_detect_intent_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"session": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session.DetectIntentResponse( + response_id="response_id_value", + output_audio=b"output_audio_blob", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session.DetectIntentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.detect_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_session.DetectIntentResponse) + assert response.response_id == "response_id_value" + assert response.output_audio == b"output_audio_blob" + + +def test_detect_intent_rest_required_fields( + request_type=gcd_session.DetectIntentRequest, +): + transport_class = transports.SessionsRestTransport + + request_init = {} + request_init["session"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).detect_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["session"] = "session_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).detect_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "session" in jsonified_request + assert jsonified_request["session"] == "session_value" + + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_session.DetectIntentResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_session.DetectIntentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.detect_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_detect_intent_rest_unset_required_fields(): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.detect_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "session", + "queryInput", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_detect_intent_rest_interceptors(null_interceptor): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.SessionsRestInterceptor(), + ) + client = SessionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionsRestInterceptor, "post_detect_intent" + ) as post, mock.patch.object( + transports.SessionsRestInterceptor, "pre_detect_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_session.DetectIntentRequest.pb( + gcd_session.DetectIntentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_session.DetectIntentResponse.to_json( + gcd_session.DetectIntentResponse() + ) + + request = gcd_session.DetectIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_session.DetectIntentResponse() + + client.detect_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_detect_intent_rest_bad_request( + transport: str = "rest", request_type=gcd_session.DetectIntentRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"session": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.detect_intent(request) + + +def test_detect_intent_rest_flattened(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session.DetectIntentResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"session": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + session="session_value", + query_input=gcd_session.QueryInput( + audio_config=audio_config.InputAudioConfig( + audio_encoding=audio_config.AudioEncoding.AUDIO_ENCODING_LINEAR_16 + ) + ), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session.DetectIntentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.detect_intent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{session=projects/*/agent/sessions/*}:detectIntent" + % client.transport._host, + args[1], + ) + + +def test_detect_intent_rest_flattened_error(transport: str = "rest"): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.detect_intent( + gcd_session.DetectIntentRequest(), + session="session_value", + query_input=gcd_session.QueryInput( + audio_config=audio_config.InputAudioConfig( + audio_encoding=audio_config.AudioEncoding.AUDIO_ENCODING_LINEAR_16 + ) + ), + ) + + +def test_detect_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_streaming_detect_intent_rest_no_http_options(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = session.StreamingDetectIntentRequest() + requests = [request] + with pytest.raises(RuntimeError): + client.streaming_detect_intent(requests) + + +def test_streaming_detect_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + # Since a `google.api.http` annotation is required for using a rest transport + # method, this should error. + with pytest.raises(NotImplementedError) as not_implemented_error: + client.streaming_detect_intent({}) + assert "Method StreamingDetectIntent is not available over REST transport" in str( + not_implemented_error.value + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.SessionsGrpcTransport( @@ -1083,6 +1416,7 @@ def test_transport_get_channel(): [ transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport, + transports.SessionsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1097,6 +1431,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1241,6 +1576,7 @@ def test_sessions_transport_auth_adc(transport_class): [ transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport, + transports.SessionsRestTransport, ], ) def test_sessions_transport_auth_gdch_credentials(transport_class): @@ -1338,11 +1674,23 @@ def test_sessions_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_sessions_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.SessionsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_sessions_host_no_port(transport_name): @@ -1353,7 +1701,11 @@ def test_sessions_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1361,6 +1713,7 @@ def test_sessions_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_sessions_host_with_port(transport_name): @@ -1371,7 +1724,36 @@ def test_sessions_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_sessions_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = SessionsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = SessionsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.detect_intent._session + session2 = client2.transport.detect_intent._session + assert session1 != session2 + session1 = client1.transport.streaming_detect_intent._session + session2 = client2.transport.streaming_detect_intent._session + assert session1 != session2 def test_sessions_grpc_transport_channel(): @@ -1732,6 +2114,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = SessionsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2449,6 +3117,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2466,6 +3135,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2/test_versions.py b/tests/unit/gapic/dialogflow_v2/test_versions.py index e0fc8c76b..c5c20274c 100644 --- a/tests/unit/gapic/dialogflow_v2/test_versions.py +++ b/tests/unit/gapic/dialogflow_v2/test_versions.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,12 +36,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2.services.versions import ( VersionsAsyncClient, @@ -95,6 +100,7 @@ def test__get_default_mtls_endpoint(): [ (VersionsClient, "grpc"), (VersionsAsyncClient, "grpc_asyncio"), + (VersionsClient, "rest"), ], ) def test_versions_client_from_service_account_info(client_class, transport_name): @@ -108,7 +114,11 @@ def test_versions_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -116,6 +126,7 @@ def test_versions_client_from_service_account_info(client_class, transport_name) [ (transports.VersionsGrpcTransport, "grpc"), (transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.VersionsRestTransport, "rest"), ], ) def test_versions_client_service_account_always_use_jwt( @@ -141,6 +152,7 @@ def test_versions_client_service_account_always_use_jwt( [ (VersionsClient, "grpc"), (VersionsAsyncClient, "grpc_asyncio"), + (VersionsClient, "rest"), ], ) def test_versions_client_from_service_account_file(client_class, transport_name): @@ -161,13 +173,18 @@ def test_versions_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_versions_client_get_transport_class(): transport = VersionsClient.get_transport_class() available_transports = [ transports.VersionsGrpcTransport, + transports.VersionsRestTransport, ] assert transport in available_transports @@ -180,6 +197,7 @@ def test_versions_client_get_transport_class(): [ (VersionsClient, transports.VersionsGrpcTransport, "grpc"), (VersionsAsyncClient, transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (VersionsClient, transports.VersionsRestTransport, "rest"), ], ) @mock.patch.object( @@ -321,6 +339,8 @@ def test_versions_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (VersionsClient, transports.VersionsRestTransport, "rest", "true"), + (VersionsClient, transports.VersionsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -510,6 +530,7 @@ def test_versions_client_get_mtls_endpoint_and_cert_source(client_class): [ (VersionsClient, transports.VersionsGrpcTransport, "grpc"), (VersionsAsyncClient, transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (VersionsClient, transports.VersionsRestTransport, "rest"), ], ) def test_versions_client_client_options_scopes( @@ -545,6 +566,7 @@ def test_versions_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (VersionsClient, transports.VersionsRestTransport, "rest", None), ], ) def test_versions_client_client_options_credentials_file( @@ -2033,171 +2055,1598 @@ async def test_delete_version_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.VersionsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + version.ListVersionsRequest, + dict, + ], +) +def test_list_versions_rest(request_type): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = VersionsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = version.ListVersionsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.VersionsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.ListVersionsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_versions(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListVersionsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_versions_rest_required_fields(request_type=version.ListVersionsRequest): + transport_class = transports.VersionsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_versions._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_versions._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = VersionsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = version.ListVersionsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = version.ListVersionsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_versions(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_versions_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_versions._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.VersionsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_versions_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = VersionsClient( - client_options=options, - transport=transport, + client = VersionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.VersionsRestInterceptor, "post_list_versions" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_list_versions" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.ListVersionsRequest.pb(version.ListVersionsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = version.ListVersionsResponse.to_json( + version.ListVersionsResponse() ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = VersionsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = version.ListVersionsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = version.ListVersionsResponse() + + client.list_versions( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.VersionsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_versions_rest_bad_request( + transport: str = "rest", request_type=version.ListVersionsRequest +): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = VersionsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.VersionsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_versions(request) + + +def test_list_versions_rest_flattened(): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = VersionsClient(transport=transport) - assert client.transport is transport + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = version.ListVersionsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.VersionsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.ListVersionsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_versions(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent}/versions" % client.transport._host, args[1] + ) + + +def test_list_versions_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.VersionsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_versions( + version.ListVersionsRequest(), + parent="parent_value", + ) + + +def test_list_versions_rest_pager(transport: str = "rest"): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + version.ListVersionsResponse( + versions=[ + version.Version(), + version.Version(), + version.Version(), + ], + next_page_token="abc", + ), + version.ListVersionsResponse( + versions=[], + next_page_token="def", + ), + version.ListVersionsResponse( + versions=[ + version.Version(), + ], + next_page_token="ghi", + ), + version.ListVersionsResponse( + versions=[ + version.Version(), + version.Version(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(version.ListVersionsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values -@pytest.mark.parametrize( - "transport_class", - [ - transports.VersionsGrpcTransport, - transports.VersionsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1/agent"} + + pager = client.list_versions(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, version.Version) for i in results) + + pages = list(client.list_versions(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + version.GetVersionRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = VersionsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name - - -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. +def test_get_version_rest(request_type): client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.VersionsGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/versions/sample2"} + request = request_type(**request_init) -def test_versions_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.VersionsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = version.Version( + name="name_value", + description="description_value", + version_number=1518, + status=version.Version.VersionStatus.IN_PROGRESS, ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_versions_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2.services.versions.transports.VersionsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.VersionsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_version(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_versions", - "get_version", - "create_version", - "update_version", - "delete_version", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + # Establish that the response is the type that we expect. + assert isinstance(response, version.Version) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.version_number == 1518 + assert response.status == version.Version.VersionStatus.IN_PROGRESS + + +def test_get_version_rest_required_fields(request_type=version.GetVersionRequest): + transport_class = transports.VersionsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + # verify required fields with default values are now present -def test_versions_base_transport_with_credentials_file(): + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = version.Version() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_version._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.VersionsRestInterceptor, "post_get_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_get_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.GetVersionRequest.pb(version.GetVersionRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = version.Version.to_json(version.Version()) + + request = version.GetVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = version.Version() + + client.get_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_version_rest_bad_request( + transport: str = "rest", request_type=version.GetVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/versions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_version(request) + + +def test_get_version_rest_flattened(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = version.Version() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/versions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_version(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/agent/versions/*}" % client.transport._host, args[1] + ) + + +def test_get_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_version( + version.GetVersionRequest(), + name="name_value", + ) + + +def test_get_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_version.CreateVersionRequest, + dict, + ], +) +def test_create_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["version"] = { + "name": "name_value", + "description": "description_value", + "version_number": 1518, + "create_time": {"seconds": 751, "nanos": 543}, + "status": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version( + name="name_value", + description="description_value", + version_number=1518, + status=gcd_version.Version.VersionStatus.IN_PROGRESS, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_version(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_version.Version) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.version_number == 1518 + assert response.status == gcd_version.Version.VersionStatus.IN_PROGRESS + + +def test_create_version_rest_required_fields( + request_type=gcd_version.CreateVersionRequest, +): + transport_class = transports.VersionsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_version._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "version", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.VersionsRestInterceptor, "post_create_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_create_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_version.CreateVersionRequest.pb( + gcd_version.CreateVersionRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_version.Version.to_json(gcd_version.Version()) + + request = gcd_version.CreateVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_version.Version() + + client.create_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_version_rest_bad_request( + transport: str = "rest", request_type=gcd_version.CreateVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["version"] = { + "name": "name_value", + "description": "description_value", + "version_number": 1518, + "create_time": {"seconds": 751, "nanos": 543}, + "status": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_version(request) + + +def test_create_version_rest_flattened(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + version=gcd_version.Version(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_version(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{parent=projects/*/agent}/versions" % client.transport._host, args[1] + ) + + +def test_create_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_version( + gcd_version.CreateVersionRequest(), + parent="parent_value", + version=gcd_version.Version(name="name_value"), + ) + + +def test_create_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_version.UpdateVersionRequest, + dict, + ], +) +def test_update_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"version": {"name": "projects/sample1/agent/versions/sample2"}} + request_init["version"] = { + "name": "projects/sample1/agent/versions/sample2", + "description": "description_value", + "version_number": 1518, + "create_time": {"seconds": 751, "nanos": 543}, + "status": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version( + name="name_value", + description="description_value", + version_number=1518, + status=gcd_version.Version.VersionStatus.IN_PROGRESS, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_version(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_version.Version) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.version_number == 1518 + assert response.status == gcd_version.Version.VersionStatus.IN_PROGRESS + + +def test_update_version_rest_required_fields( + request_type=gcd_version.UpdateVersionRequest, +): + transport_class = transports.VersionsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_version._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_version._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "version", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.VersionsRestInterceptor, "post_update_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_update_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_version.UpdateVersionRequest.pb( + gcd_version.UpdateVersionRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_version.Version.to_json(gcd_version.Version()) + + request = gcd_version.UpdateVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_version.Version() + + client.update_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_version_rest_bad_request( + transport: str = "rest", request_type=gcd_version.UpdateVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"version": {"name": "projects/sample1/agent/versions/sample2"}} + request_init["version"] = { + "name": "projects/sample1/agent/versions/sample2", + "description": "description_value", + "version_number": 1518, + "create_time": {"seconds": 751, "nanos": 543}, + "status": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_version(request) + + +def test_update_version_rest_flattened(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version() + + # get arguments that satisfy an http rule for this method + sample_request = { + "version": {"name": "projects/sample1/agent/versions/sample2"} + } + + # get truthy value for each flattened field + mock_args = dict( + version=gcd_version.Version(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_version(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{version.name=projects/*/agent/versions/*}" % client.transport._host, + args[1], + ) + + +def test_update_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_version( + gcd_version.UpdateVersionRequest(), + version=gcd_version.Version(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + version.DeleteVersionRequest, + dict, + ], +) +def test_delete_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/versions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_version(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_version_rest_required_fields(request_type=version.DeleteVersionRequest): + transport_class = transports.VersionsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_version._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.VersionsRestInterceptor, "pre_delete_version" + ) as pre: + pre.assert_not_called() + pb_message = version.DeleteVersionRequest.pb(version.DeleteVersionRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = version.DeleteVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_version_rest_bad_request( + transport: str = "rest", request_type=version.DeleteVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/versions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_version(request) + + +def test_delete_version_rest_flattened(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/versions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_version(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2/{name=projects/*/agent/versions/*}" % client.transport._host, args[1] + ) + + +def test_delete_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_version( + version.DeleteVersionRequest(), + name="name_value", + ) + + +def test_delete_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = VersionsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = VersionsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = VersionsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.VersionsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.VersionsGrpcTransport, + transports.VersionsGrpcAsyncIOTransport, + transports.VersionsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = VersionsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.VersionsGrpcTransport, + ) + + +def test_versions_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.VersionsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_versions_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2.services.versions.transports.VersionsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.VersionsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_versions", + "get_version", + "create_version", + "update_version", + "delete_version", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_versions_base_transport_with_credentials_file(): # Instantiate the base transport with a credentials file with mock.patch.object( google.auth, "load_credentials_from_file", autospec=True @@ -2275,6 +3724,7 @@ def test_versions_transport_auth_adc(transport_class): [ transports.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport, + transports.VersionsRestTransport, ], ) def test_versions_transport_auth_gdch_credentials(transport_class): @@ -2372,11 +3822,23 @@ def test_versions_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_versions_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.VersionsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_versions_host_no_port(transport_name): @@ -2387,7 +3849,11 @@ def test_versions_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2395,6 +3861,7 @@ def test_versions_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_versions_host_with_port(transport_name): @@ -2405,7 +3872,45 @@ def test_versions_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_versions_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = VersionsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = VersionsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_versions._session + session2 = client2.transport.list_versions._session + assert session1 != session2 + session1 = client1.transport.get_version._session + session2 = client2.transport.get_version._session + assert session1 != session2 + session1 = client1.transport.create_version._session + session2 = client2.transport.create_version._session + assert session1 != session2 + session1 = client1.transport.update_version._session + session2 = client2.transport.update_version._session + assert session1 != session2 + session1 = client1.transport.delete_version._session + session2 = client2.transport.delete_version._session + assert session1 != session2 def test_versions_grpc_transport_channel(): @@ -2689,6 +4194,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3406,6 +5197,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3423,6 +5215,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_agents.py b/tests/unit/gapic/dialogflow_v2beta1/test_agents.py index 475f2b204..71adecdd5 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_agents.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_agents.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -44,12 +46,15 @@ from google.oauth2 import service_account from google.protobuf import empty_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.agents import ( AgentsAsyncClient, @@ -105,6 +110,7 @@ def test__get_default_mtls_endpoint(): [ (AgentsClient, "grpc"), (AgentsAsyncClient, "grpc_asyncio"), + (AgentsClient, "rest"), ], ) def test_agents_client_from_service_account_info(client_class, transport_name): @@ -118,7 +124,11 @@ def test_agents_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -126,6 +136,7 @@ def test_agents_client_from_service_account_info(client_class, transport_name): [ (transports.AgentsGrpcTransport, "grpc"), (transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.AgentsRestTransport, "rest"), ], ) def test_agents_client_service_account_always_use_jwt(transport_class, transport_name): @@ -149,6 +160,7 @@ def test_agents_client_service_account_always_use_jwt(transport_class, transport [ (AgentsClient, "grpc"), (AgentsAsyncClient, "grpc_asyncio"), + (AgentsClient, "rest"), ], ) def test_agents_client_from_service_account_file(client_class, transport_name): @@ -169,13 +181,18 @@ def test_agents_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_agents_client_get_transport_class(): transport = AgentsClient.get_transport_class() available_transports = [ transports.AgentsGrpcTransport, + transports.AgentsRestTransport, ] assert transport in available_transports @@ -188,6 +205,7 @@ def test_agents_client_get_transport_class(): [ (AgentsClient, transports.AgentsGrpcTransport, "grpc"), (AgentsAsyncClient, transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (AgentsClient, transports.AgentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -327,6 +345,8 @@ def test_agents_client_client_options(client_class, transport_class, transport_n "grpc_asyncio", "false", ), + (AgentsClient, transports.AgentsRestTransport, "rest", "true"), + (AgentsClient, transports.AgentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -512,6 +532,7 @@ def test_agents_client_get_mtls_endpoint_and_cert_source(client_class): [ (AgentsClient, transports.AgentsGrpcTransport, "grpc"), (AgentsAsyncClient, transports.AgentsGrpcAsyncIOTransport, "grpc_asyncio"), + (AgentsClient, transports.AgentsRestTransport, "rest"), ], ) def test_agents_client_client_options_scopes( @@ -547,6 +568,7 @@ def test_agents_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (AgentsClient, transports.AgentsRestTransport, "rest", None), ], ) def test_agents_client_client_options_credentials_file( @@ -2741,169 +2763,2473 @@ async def test_get_validation_result_field_headers_async(): ) in kw["metadata"] -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.AgentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + agent.GetAgentRequest, + dict, + ], +) +def test_get_agent_rest(request_type): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = AgentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = agent.Agent( + parent="parent_value", + display_name="display_name_value", + default_language_code="default_language_code_value", + supported_language_codes=["supported_language_codes_value"], + time_zone="time_zone_value", + description="description_value", + avatar_uri="avatar_uri_value", + enable_logging=True, + match_mode=agent.Agent.MatchMode.MATCH_MODE_HYBRID, + classification_threshold=0.25520000000000004, + api_version=agent.Agent.ApiVersion.API_VERSION_V1, + tier=agent.Agent.Tier.TIER_STANDARD, ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.AgentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.Agent) + assert response.parent == "parent_value" + assert response.display_name == "display_name_value" + assert response.default_language_code == "default_language_code_value" + assert response.supported_language_codes == ["supported_language_codes_value"] + assert response.time_zone == "time_zone_value" + assert response.description == "description_value" + assert response.avatar_uri == "avatar_uri_value" + assert response.enable_logging is True + assert response.match_mode == agent.Agent.MatchMode.MATCH_MODE_HYBRID + assert math.isclose( + response.classification_threshold, 0.25520000000000004, rel_tol=1e-6 ) - with pytest.raises(ValueError): - client = AgentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + assert response.api_version == agent.Agent.ApiVersion.API_VERSION_V1 + assert response.tier == agent.Agent.Tier.TIER_STANDARD + + +def test_get_agent_rest_required_fields(request_type=agent.GetAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.AgentsGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.Agent() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = AgentsClient( - client_options=options, - transport=transport, - ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = AgentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + unset_fields = transport.get_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) - # It is an error to provide scopes and a transport instance. - transport = transports.AgentsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), ) - with pytest.raises(ValueError): - client = AgentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AgentsRestInterceptor, "post_get_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_get_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.GetAgentRequest.pb(agent.GetAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = agent.Agent.to_json(agent.Agent()) + + request = agent.GetAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.Agent() + + client.get_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) + pre.assert_called_once() + post.assert_called_once() -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.AgentsGrpcTransport( + +def test_get_agent_rest_bad_request( + transport: str = "rest", request_type=agent.GetAgentRequest +): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = AgentsClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.AgentsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_agent(request) + + +def test_get_agent_rest_flattened(): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.AgentsGrpcAsyncIOTransport( + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = agent.Agent() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_agent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/agent" % client.transport._host, args[1] + ) + + +def test_get_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_agent( + agent.GetAgentRequest(), + parent="parent_value", + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.AgentsGrpcTransport, - transports.AgentsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() +def test_get_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + gcd_agent.SetAgentRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = AgentsClient.get_transport_class(transport_name)( +def test_set_agent_rest(request_type): + client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"agent": {"parent": "projects/sample1"}} + request_init["agent"] = { + "parent": "projects/sample1", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "enable_logging": True, + "match_mode": 1, + "classification_threshold": 0.25520000000000004, + "api_version": 1, + "tier": 1, + } + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_agent.Agent( + parent="parent_value", + display_name="display_name_value", + default_language_code="default_language_code_value", + supported_language_codes=["supported_language_codes_value"], + time_zone="time_zone_value", + description="description_value", + avatar_uri="avatar_uri_value", + enable_logging=True, + match_mode=gcd_agent.Agent.MatchMode.MATCH_MODE_HYBRID, + classification_threshold=0.25520000000000004, + api_version=gcd_agent.Agent.ApiVersion.API_VERSION_V1, + tier=gcd_agent.Agent.Tier.TIER_STANDARD, + ) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. - client = AgentsClient( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.AgentsGrpcTransport, + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.set_agent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_agent.Agent) + assert response.parent == "parent_value" + assert response.display_name == "display_name_value" + assert response.default_language_code == "default_language_code_value" + assert response.supported_language_codes == ["supported_language_codes_value"] + assert response.time_zone == "time_zone_value" + assert response.description == "description_value" + assert response.avatar_uri == "avatar_uri_value" + assert response.enable_logging is True + assert response.match_mode == gcd_agent.Agent.MatchMode.MATCH_MODE_HYBRID + assert math.isclose( + response.classification_threshold, 0.25520000000000004, rel_tol=1e-6 ) + assert response.api_version == gcd_agent.Agent.ApiVersion.API_VERSION_V1 + assert response.tier == gcd_agent.Agent.Tier.TIER_STANDARD -def test_agents_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.AgentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +def test_set_agent_rest_required_fields(request_type=gcd_agent.SetAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) + # verify fields with default values are dropped -def test_agents_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2beta1.services.agents.transports.AgentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.AgentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).set_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "get_agent", - "set_agent", - "delete_agent", - "search_agents", - "train_agent", - "export_agent", - "import_agent", - "restore_agent", - "get_validation_result", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + # verify required fields with default values are now present - with pytest.raises(NotImplementedError): - transport.close() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).set_agent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client + # verify required fields with non-default values are left alone + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_agent.Agent() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.set_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_set_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.set_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("agent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_set_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AgentsRestInterceptor, "post_set_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_set_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_agent.SetAgentRequest.pb(gcd_agent.SetAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_agent.Agent.to_json(gcd_agent.Agent()) + + request = gcd_agent.SetAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_agent.Agent() + + client.set_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_set_agent_rest_bad_request( + transport: str = "rest", request_type=gcd_agent.SetAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"agent": {"parent": "projects/sample1"}} + request_init["agent"] = { + "parent": "projects/sample1", + "display_name": "display_name_value", + "default_language_code": "default_language_code_value", + "supported_language_codes": [ + "supported_language_codes_value1", + "supported_language_codes_value2", + ], + "time_zone": "time_zone_value", + "description": "description_value", + "avatar_uri": "avatar_uri_value", + "enable_logging": True, + "match_mode": 1, + "classification_threshold": 0.25520000000000004, + "api_version": 1, + "tier": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.set_agent(request) + + +def test_set_agent_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_agent.Agent() + + # get arguments that satisfy an http rule for this method + sample_request = {"agent": {"parent": "projects/sample1"}} + + # get truthy value for each flattened field + mock_args = dict( + agent=gcd_agent.Agent(parent="parent_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_agent.Agent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.set_agent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{agent.parent=projects/*}/agent" % client.transport._host, + args[1], + ) + + +def test_set_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.set_agent( + gcd_agent.SetAgentRequest(), + agent=gcd_agent.Agent(parent="parent_value"), + ) + + +def test_set_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.DeleteAgentRequest, + dict, + ], +) +def test_delete_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_agent(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_agent_rest_required_fields(request_type=agent.DeleteAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AgentsRestInterceptor, "pre_delete_agent" + ) as pre: + pre.assert_not_called() + pb_message = agent.DeleteAgentRequest.pb(agent.DeleteAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = agent.DeleteAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_agent_rest_bad_request( + transport: str = "rest", request_type=agent.DeleteAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_agent(request) + + +def test_delete_agent_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_agent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/agent" % client.transport._host, args[1] + ) + + +def test_delete_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_agent( + agent.DeleteAgentRequest(), + parent="parent_value", + ) + + +def test_delete_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.SearchAgentsRequest, + dict, + ], +) +def test_search_agents_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = agent.SearchAgentsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.SearchAgentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.search_agents(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.SearchAgentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_search_agents_rest_required_fields(request_type=agent.SearchAgentsRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_agents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).search_agents._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = agent.SearchAgentsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = agent.SearchAgentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.search_agents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_search_agents_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.search_agents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_search_agents_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AgentsRestInterceptor, "post_search_agents" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_search_agents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.SearchAgentsRequest.pb(agent.SearchAgentsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = agent.SearchAgentsResponse.to_json( + agent.SearchAgentsResponse() + ) + + request = agent.SearchAgentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = agent.SearchAgentsResponse() + + client.search_agents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_search_agents_rest_bad_request( + transport: str = "rest", request_type=agent.SearchAgentsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.search_agents(request) + + +def test_search_agents_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = agent.SearchAgentsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = agent.SearchAgentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.search_agents(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/agent:search" % client.transport._host, + args[1], + ) + + +def test_search_agents_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.search_agents( + agent.SearchAgentsRequest(), + parent="parent_value", + ) + + +def test_search_agents_rest_pager(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + agent.SearchAgentsResponse( + agents=[ + agent.Agent(), + agent.Agent(), + agent.Agent(), + ], + next_page_token="abc", + ), + agent.SearchAgentsResponse( + agents=[], + next_page_token="def", + ), + agent.SearchAgentsResponse( + agents=[ + agent.Agent(), + ], + next_page_token="ghi", + ), + agent.SearchAgentsResponse( + agents=[ + agent.Agent(), + agent.Agent(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(agent.SearchAgentsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1"} + + pager = client.search_agents(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, agent.Agent) for i in results) + + pages = list(client.search_agents(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + agent.TrainAgentRequest, + dict, + ], +) +def test_train_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.train_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_train_agent_rest_required_fields(request_type=agent.TrainAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).train_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).train_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.train_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_train_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.train_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_train_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.AgentsRestInterceptor, "post_train_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_train_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.TrainAgentRequest.pb(agent.TrainAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = agent.TrainAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.train_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_train_agent_rest_bad_request( + transport: str = "rest", request_type=agent.TrainAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.train_agent(request) + + +def test_train_agent_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.train_agent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/agent:train" % client.transport._host, + args[1], + ) + + +def test_train_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.train_agent( + agent.TrainAgentRequest(), + parent="parent_value", + ) + + +def test_train_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.ExportAgentRequest, + dict, + ], +) +def test_export_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.export_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_export_agent_rest_required_fields(request_type=agent.ExportAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).export_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).export_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.export_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_export_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.export_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_export_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.AgentsRestInterceptor, "post_export_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_export_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.ExportAgentRequest.pb(agent.ExportAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = agent.ExportAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.export_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_export_agent_rest_bad_request( + transport: str = "rest", request_type=agent.ExportAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.export_agent(request) + + +def test_export_agent_rest_flattened(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.export_agent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/agent:export" % client.transport._host, + args[1], + ) + + +def test_export_agent_rest_flattened_error(transport: str = "rest"): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.export_agent( + agent.ExportAgentRequest(), + parent="parent_value", + ) + + +def test_export_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.ImportAgentRequest, + dict, + ], +) +def test_import_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.import_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_import_agent_rest_required_fields(request_type=agent.ImportAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).import_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).import_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.import_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_import_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.import_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_import_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.AgentsRestInterceptor, "post_import_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_import_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.ImportAgentRequest.pb(agent.ImportAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = agent.ImportAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.import_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_import_agent_rest_bad_request( + transport: str = "rest", request_type=agent.ImportAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.import_agent(request) + + +def test_import_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.RestoreAgentRequest, + dict, + ], +) +def test_restore_agent_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.restore_agent(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_restore_agent_rest_required_fields(request_type=agent.RestoreAgentRequest): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).restore_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).restore_agent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.restore_agent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_restore_agent_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.restore_agent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_restore_agent_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.AgentsRestInterceptor, "post_restore_agent" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_restore_agent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.RestoreAgentRequest.pb(agent.RestoreAgentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = agent.RestoreAgentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.restore_agent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_restore_agent_rest_bad_request( + transport: str = "rest", request_type=agent.RestoreAgentRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.restore_agent(request) + + +def test_restore_agent_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + agent.GetValidationResultRequest, + dict, + ], +) +def test_get_validation_result_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = validation_result.ValidationResult() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = validation_result.ValidationResult.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_validation_result(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, validation_result.ValidationResult) + + +def test_get_validation_result_rest_required_fields( + request_type=agent.GetValidationResultRequest, +): + transport_class = transports.AgentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_validation_result._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_validation_result._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = validation_result.ValidationResult() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = validation_result.ValidationResult.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_validation_result(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_validation_result_rest_unset_required_fields(): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_validation_result._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_validation_result_rest_interceptors(null_interceptor): + transport = transports.AgentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.AgentsRestInterceptor(), + ) + client = AgentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AgentsRestInterceptor, "post_get_validation_result" + ) as post, mock.patch.object( + transports.AgentsRestInterceptor, "pre_get_validation_result" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = agent.GetValidationResultRequest.pb( + agent.GetValidationResultRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = validation_result.ValidationResult.to_json( + validation_result.ValidationResult() + ) + + request = agent.GetValidationResultRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = validation_result.ValidationResult() + + client.get_validation_result( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_validation_result_rest_bad_request( + transport: str = "rest", request_type=agent.GetValidationResultRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_validation_result(request) + + +def test_get_validation_result_rest_error(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = AgentsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = AgentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = AgentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = AgentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.AgentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.AgentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.AgentsGrpcTransport, + transports.AgentsGrpcAsyncIOTransport, + transports.AgentsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = AgentsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.AgentsGrpcTransport, + ) + + +def test_agents_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.AgentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_agents_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2beta1.services.agents.transports.AgentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.AgentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "get_agent", + "set_agent", + "delete_agent", + "search_agents", + "train_agent", + "export_agent", + "import_agent", + "restore_agent", + "get_validation_result", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client # Catch all for all remaining methods and properties remainder = [ @@ -2992,6 +5318,7 @@ def test_agents_transport_auth_adc(transport_class): [ transports.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport, + transports.AgentsRestTransport, ], ) def test_agents_transport_auth_gdch_credentials(transport_class): @@ -3089,11 +5416,40 @@ def test_agents_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_agents_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.AgentsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_agents_rest_lro_client(): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_agents_host_no_port(transport_name): @@ -3104,7 +5460,11 @@ def test_agents_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3112,6 +5472,7 @@ def test_agents_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_agents_host_with_port(transport_name): @@ -3122,7 +5483,57 @@ def test_agents_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_agents_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = AgentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = AgentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.get_agent._session + session2 = client2.transport.get_agent._session + assert session1 != session2 + session1 = client1.transport.set_agent._session + session2 = client2.transport.set_agent._session + assert session1 != session2 + session1 = client1.transport.delete_agent._session + session2 = client2.transport.delete_agent._session + assert session1 != session2 + session1 = client1.transport.search_agents._session + session2 = client2.transport.search_agents._session + assert session1 != session2 + session1 = client1.transport.train_agent._session + session2 = client2.transport.train_agent._session + assert session1 != session2 + session1 = client1.transport.export_agent._session + session2 = client2.transport.export_agent._session + assert session1 != session2 + session1 = client1.transport.import_agent._session + session2 = client2.transport.import_agent._session + assert session1 != session2 + session1 = client1.transport.restore_agent._session + session2 = client2.transport.restore_agent._session + assert session1 != session2 + session1 = client1.transport.get_validation_result._session + session2 = client2.transport.get_validation_result._session + assert session1 != session2 def test_agents_grpc_transport_channel(): @@ -3437,6 +5848,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = AgentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = AgentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4154,6 +6851,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4171,6 +6869,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_answer_records.py b/tests/unit/gapic/dialogflow_v2beta1/test_answer_records.py index 624f1056a..d74dbca12 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_answer_records.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_answer_records.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,12 +36,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.answer_records import ( AnswerRecordsAsyncClient, @@ -101,6 +106,7 @@ def test__get_default_mtls_endpoint(): [ (AnswerRecordsClient, "grpc"), (AnswerRecordsAsyncClient, "grpc_asyncio"), + (AnswerRecordsClient, "rest"), ], ) def test_answer_records_client_from_service_account_info(client_class, transport_name): @@ -114,7 +120,11 @@ def test_answer_records_client_from_service_account_info(client_class, transport assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -122,6 +132,7 @@ def test_answer_records_client_from_service_account_info(client_class, transport [ (transports.AnswerRecordsGrpcTransport, "grpc"), (transports.AnswerRecordsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.AnswerRecordsRestTransport, "rest"), ], ) def test_answer_records_client_service_account_always_use_jwt( @@ -147,6 +158,7 @@ def test_answer_records_client_service_account_always_use_jwt( [ (AnswerRecordsClient, "grpc"), (AnswerRecordsAsyncClient, "grpc_asyncio"), + (AnswerRecordsClient, "rest"), ], ) def test_answer_records_client_from_service_account_file(client_class, transport_name): @@ -167,13 +179,18 @@ def test_answer_records_client_from_service_account_file(client_class, transport assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_answer_records_client_get_transport_class(): transport = AnswerRecordsClient.get_transport_class() available_transports = [ transports.AnswerRecordsGrpcTransport, + transports.AnswerRecordsRestTransport, ] assert transport in available_transports @@ -190,6 +207,7 @@ def test_answer_records_client_get_transport_class(): transports.AnswerRecordsGrpcAsyncIOTransport, "grpc_asyncio", ), + (AnswerRecordsClient, transports.AnswerRecordsRestTransport, "rest"), ], ) @mock.patch.object( @@ -335,6 +353,8 @@ def test_answer_records_client_client_options( "grpc_asyncio", "false", ), + (AnswerRecordsClient, transports.AnswerRecordsRestTransport, "rest", "true"), + (AnswerRecordsClient, transports.AnswerRecordsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -534,6 +554,7 @@ def test_answer_records_client_get_mtls_endpoint_and_cert_source(client_class): transports.AnswerRecordsGrpcAsyncIOTransport, "grpc_asyncio", ), + (AnswerRecordsClient, transports.AnswerRecordsRestTransport, "rest"), ], ) def test_answer_records_client_client_options_scopes( @@ -574,6 +595,7 @@ def test_answer_records_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (AnswerRecordsClient, transports.AnswerRecordsRestTransport, "rest", None), ], ) def test_answer_records_client_client_options_credentials_file( @@ -1554,6 +1576,720 @@ async def test_update_answer_record_flattened_error_async(): ) +@pytest.mark.parametrize( + "request_type", + [ + answer_record.GetAnswerRecordRequest, + dict, + ], +) +def test_get_answer_record_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/answerRecords/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = answer_record.AnswerRecord( + name="name_value", + agent_assistant_record=answer_record.AgentAssistantRecord( + article_suggestion_answer=participant.ArticleAnswer(title="title_value") + ), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = answer_record.AnswerRecord.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_answer_record(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, answer_record.AnswerRecord) + assert response.name == "name_value" + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_answer_record_rest_interceptors(null_interceptor): + transport = transports.AnswerRecordsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AnswerRecordsRestInterceptor(), + ) + client = AnswerRecordsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AnswerRecordsRestInterceptor, "post_get_answer_record" + ) as post, mock.patch.object( + transports.AnswerRecordsRestInterceptor, "pre_get_answer_record" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = answer_record.GetAnswerRecordRequest.pb( + answer_record.GetAnswerRecordRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = answer_record.AnswerRecord.to_json( + answer_record.AnswerRecord() + ) + + request = answer_record.GetAnswerRecordRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = answer_record.AnswerRecord() + + client.get_answer_record( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_answer_record_rest_bad_request( + transport: str = "rest", request_type=answer_record.GetAnswerRecordRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/answerRecords/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_answer_record(request) + + +def test_get_answer_record_rest_error(): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + answer_record.ListAnswerRecordsRequest, + dict, + ], +) +def test_list_answer_records_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = answer_record.ListAnswerRecordsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = answer_record.ListAnswerRecordsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_answer_records(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListAnswerRecordsPager) + assert response.next_page_token == "next_page_token_value" + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_answer_records_rest_interceptors(null_interceptor): + transport = transports.AnswerRecordsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AnswerRecordsRestInterceptor(), + ) + client = AnswerRecordsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AnswerRecordsRestInterceptor, "post_list_answer_records" + ) as post, mock.patch.object( + transports.AnswerRecordsRestInterceptor, "pre_list_answer_records" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = answer_record.ListAnswerRecordsRequest.pb( + answer_record.ListAnswerRecordsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = answer_record.ListAnswerRecordsResponse.to_json( + answer_record.ListAnswerRecordsResponse() + ) + + request = answer_record.ListAnswerRecordsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = answer_record.ListAnswerRecordsResponse() + + client.list_answer_records( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_answer_records_rest_bad_request( + transport: str = "rest", request_type=answer_record.ListAnswerRecordsRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_answer_records(request) + + +def test_list_answer_records_rest_flattened(): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = answer_record.ListAnswerRecordsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = answer_record.ListAnswerRecordsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_answer_records(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/answerRecords" % client.transport._host, + args[1], + ) + + +def test_list_answer_records_rest_flattened_error(transport: str = "rest"): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_answer_records( + answer_record.ListAnswerRecordsRequest(), + parent="parent_value", + ) + + +def test_list_answer_records_rest_pager(transport: str = "rest"): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + answer_record.ListAnswerRecordsResponse( + answer_records=[ + answer_record.AnswerRecord(), + answer_record.AnswerRecord(), + answer_record.AnswerRecord(), + ], + next_page_token="abc", + ), + answer_record.ListAnswerRecordsResponse( + answer_records=[], + next_page_token="def", + ), + answer_record.ListAnswerRecordsResponse( + answer_records=[ + answer_record.AnswerRecord(), + ], + next_page_token="ghi", + ), + answer_record.ListAnswerRecordsResponse( + answer_records=[ + answer_record.AnswerRecord(), + answer_record.AnswerRecord(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + answer_record.ListAnswerRecordsResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1"} + + pager = client.list_answer_records(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, answer_record.AnswerRecord) for i in results) + + pages = list(client.list_answer_records(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_answer_record.UpdateAnswerRecordRequest, + dict, + ], +) +def test_update_answer_record_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"answer_record": {"name": "projects/sample1/answerRecords/sample2"}} + request_init["answer_record"] = { + "name": "projects/sample1/answerRecords/sample2", + "answer_feedback": { + "correctness_level": 1, + "agent_assistant_detail_feedback": { + "answer_relevance": 1, + "document_correctness": 1, + "document_efficiency": 1, + "summarization_feedback": { + "start_timestamp": {"seconds": 751, "nanos": 543}, + "submit_timestamp": {}, + "summary_text": "summary_text_value", + }, + }, + "clicked": True, + "click_time": {}, + "displayed": True, + "display_time": {}, + }, + "agent_assistant_record": { + "article_suggestion_answer": { + "title": "title_value", + "uri": "uri_value", + "snippets": ["snippets_value1", "snippets_value2"], + "metadata": {}, + "answer_record": "answer_record_value", + }, + "faq_answer": { + "answer": "answer_value", + "confidence": 0.1038, + "question": "question_value", + "source": "source_value", + "metadata": {}, + "answer_record": "answer_record_value", + }, + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_answer_record.AnswerRecord( + name="name_value", + agent_assistant_record=gcd_answer_record.AgentAssistantRecord( + article_suggestion_answer=participant.ArticleAnswer(title="title_value") + ), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_answer_record.AnswerRecord.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_answer_record(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_answer_record.AnswerRecord) + assert response.name == "name_value" + + +def test_update_answer_record_rest_required_fields( + request_type=gcd_answer_record.UpdateAnswerRecordRequest, +): + transport_class = transports.AnswerRecordsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_answer_record._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_answer_record._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_answer_record.AnswerRecord() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_answer_record.AnswerRecord.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_answer_record(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_answer_record_rest_unset_required_fields(): + transport = transports.AnswerRecordsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_answer_record._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("answerRecord",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_answer_record_rest_interceptors(null_interceptor): + transport = transports.AnswerRecordsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.AnswerRecordsRestInterceptor(), + ) + client = AnswerRecordsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.AnswerRecordsRestInterceptor, "post_update_answer_record" + ) as post, mock.patch.object( + transports.AnswerRecordsRestInterceptor, "pre_update_answer_record" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_answer_record.UpdateAnswerRecordRequest.pb( + gcd_answer_record.UpdateAnswerRecordRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_answer_record.AnswerRecord.to_json( + gcd_answer_record.AnswerRecord() + ) + + request = gcd_answer_record.UpdateAnswerRecordRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_answer_record.AnswerRecord() + + client.update_answer_record( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_answer_record_rest_bad_request( + transport: str = "rest", request_type=gcd_answer_record.UpdateAnswerRecordRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"answer_record": {"name": "projects/sample1/answerRecords/sample2"}} + request_init["answer_record"] = { + "name": "projects/sample1/answerRecords/sample2", + "answer_feedback": { + "correctness_level": 1, + "agent_assistant_detail_feedback": { + "answer_relevance": 1, + "document_correctness": 1, + "document_efficiency": 1, + "summarization_feedback": { + "start_timestamp": {"seconds": 751, "nanos": 543}, + "submit_timestamp": {}, + "summary_text": "summary_text_value", + }, + }, + "clicked": True, + "click_time": {}, + "displayed": True, + "display_time": {}, + }, + "agent_assistant_record": { + "article_suggestion_answer": { + "title": "title_value", + "uri": "uri_value", + "snippets": ["snippets_value1", "snippets_value2"], + "metadata": {}, + "answer_record": "answer_record_value", + }, + "faq_answer": { + "answer": "answer_value", + "confidence": 0.1038, + "question": "question_value", + "source": "source_value", + "metadata": {}, + "answer_record": "answer_record_value", + }, + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_answer_record(request) + + +def test_update_answer_record_rest_flattened(): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_answer_record.AnswerRecord() + + # get arguments that satisfy an http rule for this method + sample_request = { + "answer_record": {"name": "projects/sample1/answerRecords/sample2"} + } + + # get truthy value for each flattened field + mock_args = dict( + answer_record=gcd_answer_record.AnswerRecord(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_answer_record.AnswerRecord.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_answer_record(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{answer_record.name=projects/*/answerRecords/*}" + % client.transport._host, + args[1], + ) + + +def test_update_answer_record_rest_flattened_error(transport: str = "rest"): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_answer_record( + gcd_answer_record.UpdateAnswerRecordRequest(), + answer_record=gcd_answer_record.AnswerRecord(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_answer_record_rest_error(): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.AnswerRecordsGrpcTransport( @@ -1635,6 +2371,7 @@ def test_transport_get_channel(): [ transports.AnswerRecordsGrpcTransport, transports.AnswerRecordsGrpcAsyncIOTransport, + transports.AnswerRecordsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1649,6 +2386,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1794,6 +2532,7 @@ def test_answer_records_transport_auth_adc(transport_class): [ transports.AnswerRecordsGrpcTransport, transports.AnswerRecordsGrpcAsyncIOTransport, + transports.AnswerRecordsRestTransport, ], ) def test_answer_records_transport_auth_gdch_credentials(transport_class): @@ -1894,11 +2633,23 @@ def test_answer_records_grpc_transport_client_cert_source_for_mtls(transport_cla ) +def test_answer_records_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.AnswerRecordsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_answer_records_host_no_port(transport_name): @@ -1909,7 +2660,11 @@ def test_answer_records_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1917,6 +2672,7 @@ def test_answer_records_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_answer_records_host_with_port(transport_name): @@ -1927,7 +2683,39 @@ def test_answer_records_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_answer_records_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = AnswerRecordsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = AnswerRecordsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.get_answer_record._session + session2 = client2.transport.get_answer_record._session + assert session1 != session2 + session1 = client1.transport.list_answer_records._session + session2 = client2.transport.list_answer_records._session + assert session1 != session2 + session1 = client1.transport.update_answer_record._session + session2 = client2.transport.update_answer_record._session + assert session1 != session2 def test_answer_records_grpc_transport_channel(): @@ -2217,6 +3005,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = AnswerRecordsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = AnswerRecordsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2934,6 +4008,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2951,6 +4026,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_contexts.py b/tests/unit/gapic/dialogflow_v2beta1/test_contexts.py index 7de0b5e14..0e6e273a4 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_contexts.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_contexts.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,12 +36,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.contexts import ( ContextsAsyncClient, @@ -95,6 +100,7 @@ def test__get_default_mtls_endpoint(): [ (ContextsClient, "grpc"), (ContextsAsyncClient, "grpc_asyncio"), + (ContextsClient, "rest"), ], ) def test_contexts_client_from_service_account_info(client_class, transport_name): @@ -108,7 +114,11 @@ def test_contexts_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -116,6 +126,7 @@ def test_contexts_client_from_service_account_info(client_class, transport_name) [ (transports.ContextsGrpcTransport, "grpc"), (transports.ContextsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ContextsRestTransport, "rest"), ], ) def test_contexts_client_service_account_always_use_jwt( @@ -141,6 +152,7 @@ def test_contexts_client_service_account_always_use_jwt( [ (ContextsClient, "grpc"), (ContextsAsyncClient, "grpc_asyncio"), + (ContextsClient, "rest"), ], ) def test_contexts_client_from_service_account_file(client_class, transport_name): @@ -161,13 +173,18 @@ def test_contexts_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_contexts_client_get_transport_class(): transport = ContextsClient.get_transport_class() available_transports = [ transports.ContextsGrpcTransport, + transports.ContextsRestTransport, ] assert transport in available_transports @@ -180,6 +197,7 @@ def test_contexts_client_get_transport_class(): [ (ContextsClient, transports.ContextsGrpcTransport, "grpc"), (ContextsAsyncClient, transports.ContextsGrpcAsyncIOTransport, "grpc_asyncio"), + (ContextsClient, transports.ContextsRestTransport, "rest"), ], ) @mock.patch.object( @@ -321,6 +339,8 @@ def test_contexts_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (ContextsClient, transports.ContextsRestTransport, "rest", "true"), + (ContextsClient, transports.ContextsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -510,6 +530,7 @@ def test_contexts_client_get_mtls_endpoint_and_cert_source(client_class): [ (ContextsClient, transports.ContextsGrpcTransport, "grpc"), (ContextsAsyncClient, transports.ContextsGrpcAsyncIOTransport, "grpc_asyncio"), + (ContextsClient, transports.ContextsRestTransport, "rest"), ], ) def test_contexts_client_client_options_scopes( @@ -545,6 +566,7 @@ def test_contexts_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (ContextsClient, transports.ContextsRestTransport, "rest", None), ], ) def test_contexts_client_client_options_credentials_file( @@ -2243,175 +2265,1844 @@ async def test_delete_all_contexts_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ContextsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + context.ListContextsRequest, + dict, + ], +) +def test_list_contexts_rest(request_type): + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ContextsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = context.ListContextsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ContextsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = context.ListContextsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_contexts(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListContextsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_contexts_rest_required_fields(request_type=context.ListContextsRequest): + transport_class = transports.ContextsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_contexts._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_contexts._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ContextsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = context.ListContextsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = context.ListContextsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_contexts(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_contexts_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_contexts._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.ContextsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_contexts_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ContextsClient( - client_options=options, - transport=transport, + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "post_list_contexts" + ) as post, mock.patch.object( + transports.ContextsRestInterceptor, "pre_list_contexts" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = context.ListContextsRequest.pb(context.ListContextsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = context.ListContextsResponse.to_json( + context.ListContextsResponse() ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ContextsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = context.ListContextsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = context.ListContextsResponse() + + client.list_contexts( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.ContextsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_contexts_rest_bad_request( + transport: str = "rest", request_type=context.ListContextsRequest +): + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = ContextsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ContextsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_contexts(request) + + +def test_list_contexts_rest_flattened(): + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = ContextsClient(transport=transport) - assert client.transport is transport + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = context.ListContextsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ContextsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = context.ListContextsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_contexts(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent/sessions/*}/contexts" + % client.transport._host, + args[1], + ) + + +def test_list_contexts_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.ContextsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_contexts( + context.ListContextsRequest(), + parent="parent_value", + ) + + +def test_list_contexts_rest_pager(transport: str = "rest"): + client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + context.ListContextsResponse( + contexts=[ + context.Context(), + context.Context(), + context.Context(), + ], + next_page_token="abc", + ), + context.ListContextsResponse( + contexts=[], + next_page_token="def", + ), + context.ListContextsResponse( + contexts=[ + context.Context(), + ], + next_page_token="ghi", + ), + context.ListContextsResponse( + contexts=[ + context.Context(), + context.Context(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(context.ListContextsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values -@pytest.mark.parametrize( - "transport_class", - [ - transports.ContextsGrpcTransport, - transports.ContextsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + pager = client.list_contexts(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, context.Context) for i in results) + + pages = list(client.list_contexts(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + context.GetContextRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = ContextsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name - - -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. +def test_get_context_rest(request_type): client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.ContextsGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + request = request_type(**request_init) -def test_contexts_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ContextsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = context.Context( + name="name_value", + lifespan_count=1498, ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_contexts_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2beta1.services.contexts.transports.ContextsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ContextsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_context(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_contexts", - "get_context", - "create_context", - "update_context", - "delete_context", - "delete_all_contexts", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + # Establish that the response is the type that we expect. + assert isinstance(response, context.Context) + assert response.name == "name_value" + assert response.lifespan_count == 1498 + + +def test_get_context_rest_required_fields(request_type=context.GetContextRequest): + transport_class = transports.ContextsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + # verify required fields with default values are now present -def test_contexts_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = context.Context() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_context(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_context_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_context._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_context_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), + ) + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "post_get_context" + ) as post, mock.patch.object( + transports.ContextsRestInterceptor, "pre_get_context" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = context.GetContextRequest.pb(context.GetContextRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = context.Context.to_json(context.Context()) + + request = context.GetContextRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = context.Context() + + client.get_context( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_context_rest_bad_request( + transport: str = "rest", request_type=context.GetContextRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_context(request) + + +def test_get_context_rest_flattened(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = context.Context() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/agent/sessions/sample2/contexts/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_context(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/agent/sessions/*/contexts/*}" + % client.transport._host, + args[1], + ) + + +def test_get_context_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_context( + context.GetContextRequest(), + name="name_value", + ) + + +def test_get_context_rest_error(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_context.CreateContextRequest, + dict, + ], +) +def test_create_context_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request_init["context"] = { + "name": "name_value", + "lifespan_count": 1498, + "parameters": {"fields": {}}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context( + name="name_value", + lifespan_count=1498, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_context(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_context.Context) + assert response.name == "name_value" + assert response.lifespan_count == 1498 + + +def test_create_context_rest_required_fields( + request_type=gcd_context.CreateContextRequest, +): + transport_class = transports.ContextsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_context(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_context_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_context._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "context", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_context_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), + ) + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "post_create_context" + ) as post, mock.patch.object( + transports.ContextsRestInterceptor, "pre_create_context" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_context.CreateContextRequest.pb( + gcd_context.CreateContextRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_context.Context.to_json(gcd_context.Context()) + + request = gcd_context.CreateContextRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_context.Context() + + client.create_context( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_context_rest_bad_request( + transport: str = "rest", request_type=gcd_context.CreateContextRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request_init["context"] = { + "name": "name_value", + "lifespan_count": 1498, + "parameters": {"fields": {}}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_context(request) + + +def test_create_context_rest_flattened(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + context=gcd_context.Context(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_context(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent/sessions/*}/contexts" + % client.transport._host, + args[1], + ) + + +def test_create_context_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_context( + gcd_context.CreateContextRequest(), + parent="parent_value", + context=gcd_context.Context(name="name_value"), + ) + + +def test_create_context_rest_error(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_context.UpdateContextRequest, + dict, + ], +) +def test_update_context_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "context": {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + } + request_init["context"] = { + "name": "projects/sample1/agent/sessions/sample2/contexts/sample3", + "lifespan_count": 1498, + "parameters": {"fields": {}}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context( + name="name_value", + lifespan_count=1498, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_context(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_context.Context) + assert response.name == "name_value" + assert response.lifespan_count == 1498 + + +def test_update_context_rest_required_fields( + request_type=gcd_context.UpdateContextRequest, +): + transport_class = transports.ContextsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_context._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_context(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_context_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_context._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("context",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_context_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), + ) + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "post_update_context" + ) as post, mock.patch.object( + transports.ContextsRestInterceptor, "pre_update_context" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_context.UpdateContextRequest.pb( + gcd_context.UpdateContextRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_context.Context.to_json(gcd_context.Context()) + + request = gcd_context.UpdateContextRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_context.Context() + + client.update_context( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_context_rest_bad_request( + transport: str = "rest", request_type=gcd_context.UpdateContextRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "context": {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + } + request_init["context"] = { + "name": "projects/sample1/agent/sessions/sample2/contexts/sample3", + "lifespan_count": 1498, + "parameters": {"fields": {}}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_context(request) + + +def test_update_context_rest_flattened(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_context.Context() + + # get arguments that satisfy an http rule for this method + sample_request = { + "context": { + "name": "projects/sample1/agent/sessions/sample2/contexts/sample3" + } + } + + # get truthy value for each flattened field + mock_args = dict( + context=gcd_context.Context(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_context.Context.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_context(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{context.name=projects/*/agent/sessions/*/contexts/*}" + % client.transport._host, + args[1], + ) + + +def test_update_context_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_context( + gcd_context.UpdateContextRequest(), + context=gcd_context.Context(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_context_rest_error(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + context.DeleteContextRequest, + dict, + ], +) +def test_delete_context_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_context(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_context_rest_required_fields(request_type=context.DeleteContextRequest): + transport_class = transports.ContextsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_context._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_context(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_context_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_context._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_context_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), + ) + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "pre_delete_context" + ) as pre: + pre.assert_not_called() + pb_message = context.DeleteContextRequest.pb(context.DeleteContextRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = context.DeleteContextRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_context( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_context_rest_bad_request( + transport: str = "rest", request_type=context.DeleteContextRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/sessions/sample2/contexts/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_context(request) + + +def test_delete_context_rest_flattened(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/agent/sessions/sample2/contexts/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_context(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/agent/sessions/*/contexts/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_context_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_context( + context.DeleteContextRequest(), + name="name_value", + ) + + +def test_delete_context_rest_error(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + context.DeleteAllContextsRequest, + dict, + ], +) +def test_delete_all_contexts_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_all_contexts(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_all_contexts_rest_required_fields( + request_type=context.DeleteAllContextsRequest, +): + transport_class = transports.ContextsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_all_contexts._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_all_contexts._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_all_contexts(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_all_contexts_rest_unset_required_fields(): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_all_contexts._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_all_contexts_rest_interceptors(null_interceptor): + transport = transports.ContextsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.ContextsRestInterceptor(), + ) + client = ContextsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ContextsRestInterceptor, "pre_delete_all_contexts" + ) as pre: + pre.assert_not_called() + pb_message = context.DeleteAllContextsRequest.pb( + context.DeleteAllContextsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = context.DeleteAllContextsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_all_contexts( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_all_contexts_rest_bad_request( + transport: str = "rest", request_type=context.DeleteAllContextsRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_all_contexts(request) + + +def test_delete_all_contexts_rest_flattened(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_all_contexts(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent/sessions/*}/contexts" + % client.transport._host, + args[1], + ) + + +def test_delete_all_contexts_rest_flattened_error(transport: str = "rest"): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_all_contexts( + context.DeleteAllContextsRequest(), + parent="parent_value", + ) + + +def test_delete_all_contexts_rest_error(): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ContextsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ContextsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ContextsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ContextsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ContextsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ContextsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ContextsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ContextsGrpcTransport, + transports.ContextsGrpcAsyncIOTransport, + transports.ContextsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = ContextsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ContextsGrpcTransport, + ) + + +def test_contexts_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ContextsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_contexts_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2beta1.services.contexts.transports.ContextsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ContextsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_contexts", + "get_context", + "create_context", + "update_context", + "delete_context", + "delete_all_contexts", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_contexts_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True ) as load_creds, mock.patch( "google.cloud.dialogflow_v2beta1.services.contexts.transports.ContextsTransport._prep_wrapped_messages" ) as Transport: @@ -2486,6 +4177,7 @@ def test_contexts_transport_auth_adc(transport_class): [ transports.ContextsGrpcTransport, transports.ContextsGrpcAsyncIOTransport, + transports.ContextsRestTransport, ], ) def test_contexts_transport_auth_gdch_credentials(transport_class): @@ -2583,11 +4275,23 @@ def test_contexts_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_contexts_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.ContextsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_contexts_host_no_port(transport_name): @@ -2598,7 +4302,11 @@ def test_contexts_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2606,6 +4314,7 @@ def test_contexts_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_contexts_host_with_port(transport_name): @@ -2616,7 +4325,48 @@ def test_contexts_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_contexts_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ContextsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ContextsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_contexts._session + session2 = client2.transport.list_contexts._session + assert session1 != session2 + session1 = client1.transport.get_context._session + session2 = client2.transport.get_context._session + assert session1 != session2 + session1 = client1.transport.create_context._session + session2 = client2.transport.create_context._session + assert session1 != session2 + session1 = client1.transport.update_context._session + session2 = client2.transport.update_context._session + assert session1 != session2 + session1 = client1.transport.delete_context._session + session2 = client2.transport.delete_context._session + assert session1 != session2 + session1 = client1.transport.delete_all_contexts._session + session2 = client2.transport.delete_all_contexts._session + assert session1 != session2 def test_contexts_grpc_transport_channel(): @@ -2903,6 +4653,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ContextsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ContextsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3620,6 +5656,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3637,6 +5674,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_conversation_profiles.py b/tests/unit/gapic/dialogflow_v2beta1/test_conversation_profiles.py index cd837b18f..6ee31135d 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_conversation_profiles.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_conversation_profiles.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -43,12 +45,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.conversation_profiles import ( ConversationProfilesAsyncClient, @@ -114,6 +119,7 @@ def test__get_default_mtls_endpoint(): [ (ConversationProfilesClient, "grpc"), (ConversationProfilesAsyncClient, "grpc_asyncio"), + (ConversationProfilesClient, "rest"), ], ) def test_conversation_profiles_client_from_service_account_info( @@ -129,7 +135,11 @@ def test_conversation_profiles_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -137,6 +147,7 @@ def test_conversation_profiles_client_from_service_account_info( [ (transports.ConversationProfilesGrpcTransport, "grpc"), (transports.ConversationProfilesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ConversationProfilesRestTransport, "rest"), ], ) def test_conversation_profiles_client_service_account_always_use_jwt( @@ -162,6 +173,7 @@ def test_conversation_profiles_client_service_account_always_use_jwt( [ (ConversationProfilesClient, "grpc"), (ConversationProfilesAsyncClient, "grpc_asyncio"), + (ConversationProfilesClient, "rest"), ], ) def test_conversation_profiles_client_from_service_account_file( @@ -184,13 +196,18 @@ def test_conversation_profiles_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_conversation_profiles_client_get_transport_class(): transport = ConversationProfilesClient.get_transport_class() available_transports = [ transports.ConversationProfilesGrpcTransport, + transports.ConversationProfilesRestTransport, ] assert transport in available_transports @@ -211,6 +228,11 @@ def test_conversation_profiles_client_get_transport_class(): transports.ConversationProfilesGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + ConversationProfilesClient, + transports.ConversationProfilesRestTransport, + "rest", + ), ], ) @mock.patch.object( @@ -366,6 +388,18 @@ def test_conversation_profiles_client_client_options( "grpc_asyncio", "false", ), + ( + ConversationProfilesClient, + transports.ConversationProfilesRestTransport, + "rest", + "true", + ), + ( + ConversationProfilesClient, + transports.ConversationProfilesRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -569,6 +603,11 @@ def test_conversation_profiles_client_get_mtls_endpoint_and_cert_source(client_c transports.ConversationProfilesGrpcAsyncIOTransport, "grpc_asyncio", ), + ( + ConversationProfilesClient, + transports.ConversationProfilesRestTransport, + "rest", + ), ], ) def test_conversation_profiles_client_client_options_scopes( @@ -609,6 +648,12 @@ def test_conversation_profiles_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + ConversationProfilesClient, + transports.ConversationProfilesRestTransport, + "rest", + None, + ), ], ) def test_conversation_profiles_client_client_options_credentials_file( @@ -2713,172 +2758,2492 @@ async def test_clear_suggestion_feature_config_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ConversationProfilesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + conversation_profile.ListConversationProfilesRequest, + dict, + ], +) +def test_list_conversation_profiles_rest(request_type): + client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ConversationProfilesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ListConversationProfilesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ConversationProfilesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = ConversationProfilesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_profile.ListConversationProfilesResponse.pb( + return_value ) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide an api_key and a transport instance. - transport = transports.ConversationProfilesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationProfilesClient( - client_options=options, - transport=transport, + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_conversation_profiles(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListConversationProfilesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_conversation_profiles_rest_required_fields( + request_type=conversation_profile.ListConversationProfilesRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationProfilesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversation_profiles._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversation_profiles._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", ) + ) + jsonified_request.update(unset_fields) - # It is an error to provide scopes and a transport instance. - transport = transports.ConversationProfilesGrpcTransport( + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ListConversationProfilesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation_profile.ListConversationProfilesResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_conversation_profiles(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_conversation_profiles_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - with pytest.raises(ValueError): - client = ConversationProfilesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + + unset_fields = transport.list_conversation_profiles._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationProfilesGrpcTransport( +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_conversation_profiles_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), ) client = ConversationProfilesClient(transport=transport) - assert client.transport is transport + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "post_list_conversation_profiles", + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, "pre_list_conversation_profiles" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_profile.ListConversationProfilesRequest.pb( + conversation_profile.ListConversationProfilesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + conversation_profile.ListConversationProfilesResponse.to_json( + conversation_profile.ListConversationProfilesResponse() + ) + ) + request = conversation_profile.ListConversationProfilesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation_profile.ListConversationProfilesResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationProfilesGrpcTransport( + client.list_conversation_profiles( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_conversation_profiles_rest_bad_request( + transport: str = "rest", + request_type=conversation_profile.ListConversationProfilesRequest, +): + client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.ConversationProfilesGrpcAsyncIOTransport( + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_conversation_profiles(request) + + +def test_list_conversation_profiles_rest_flattened(): + client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ListConversationProfilesResponse() -@pytest.mark.parametrize( - "transport_class", - [ - transports.ConversationProfilesGrpcTransport, - transports.ConversationProfilesGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = ConversationProfilesClient.get_transport_class(transport_name)( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_profile.ListConversationProfilesResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_conversation_profiles(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/conversationProfiles" + % client.transport._host, + args[1], + ) + + +def test_list_conversation_profiles_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - assert transport.kind == transport_name + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_conversation_profiles( + conversation_profile.ListConversationProfilesRequest(), + parent="parent_value", + ) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. +def test_list_conversation_profiles_rest_pager(transport: str = "rest"): client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.ConversationProfilesGrpcTransport, + transport=transport, ) + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + conversation_profile.ListConversationProfilesResponse( + conversation_profiles=[ + conversation_profile.ConversationProfile(), + conversation_profile.ConversationProfile(), + conversation_profile.ConversationProfile(), + ], + next_page_token="abc", + ), + conversation_profile.ListConversationProfilesResponse( + conversation_profiles=[], + next_page_token="def", + ), + conversation_profile.ListConversationProfilesResponse( + conversation_profiles=[ + conversation_profile.ConversationProfile(), + ], + next_page_token="ghi", + ), + conversation_profile.ListConversationProfilesResponse( + conversation_profiles=[ + conversation_profile.ConversationProfile(), + conversation_profile.ConversationProfile(), + ], + ), + ) + # Two responses for two calls + response = response + response -def test_conversation_profiles_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ConversationProfilesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # Wrap the values into proper Response objs + response = tuple( + conversation_profile.ListConversationProfilesResponse.to_json(x) + for x in response ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + sample_request = {"parent": "projects/sample1"} -def test_conversation_profiles_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2beta1.services.conversation_profiles.transports.ConversationProfilesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ConversationProfilesTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + pager = client.list_conversation_profiles(request=sample_request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_conversation_profiles", - "get_conversation_profile", - "create_conversation_profile", - "update_conversation_profile", - "delete_conversation_profile", - "set_suggestion_feature_config", - "clear_suggestion_feature_config", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + results = list(pager) + assert len(results) == 6 + assert all( + isinstance(i, conversation_profile.ConversationProfile) for i in results + ) - with pytest.raises(NotImplementedError): - transport.close() + pages = list(client.list_conversation_profiles(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] +@pytest.mark.parametrize( + "request_type", + [ + conversation_profile.GetConversationProfileRequest, + dict, + ], +) +def test_get_conversation_profile_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationProfiles/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ConversationProfile( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + time_zone="time_zone_value", + security_settings="security_settings_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_conversation_profile(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, conversation_profile.ConversationProfile) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + assert response.time_zone == "time_zone_value" + assert response.security_settings == "security_settings_value" + + +def test_get_conversation_profile_rest_required_fields( + request_type=conversation_profile.GetConversationProfileRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ConversationProfile() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_conversation_profile(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_conversation_profile_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_conversation_profile._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_conversation_profile_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationProfilesRestInterceptor, "post_get_conversation_profile" + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, "pre_get_conversation_profile" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation_profile.GetConversationProfileRequest.pb( + conversation_profile.GetConversationProfileRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation_profile.ConversationProfile.to_json( + conversation_profile.ConversationProfile() + ) + + request = conversation_profile.GetConversationProfileRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation_profile.ConversationProfile() + + client.get_conversation_profile( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_conversation_profile_rest_bad_request( + transport: str = "rest", + request_type=conversation_profile.GetConversationProfileRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationProfiles/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_conversation_profile(request) + + +def test_get_conversation_profile_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation_profile.ConversationProfile() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/conversationProfiles/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_conversation_profile(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/conversationProfiles/*}" + % client.transport._host, + args[1], + ) + + +def test_get_conversation_profile_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_conversation_profile( + conversation_profile.GetConversationProfileRequest(), + name="name_value", + ) + + +def test_get_conversation_profile_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation_profile.CreateConversationProfileRequest, + dict, + ], +) +def test_create_conversation_profile_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["conversation_profile"] = { + "name": "name_value", + "display_name": "display_name_value", + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "automated_agent_config": {"agent": "agent_value"}, + "human_agent_assistant_config": { + "notification_config": {"topic": "topic_value", "message_format": 1}, + "human_agent_suggestion_config": { + "feature_configs": [ + { + "suggestion_feature": {"type_": 1}, + "enable_event_based_suggestion": True, + "suggestion_trigger_settings": { + "no_small_talk": True, + "only_end_user": True, + }, + "query_config": { + "knowledge_base_query_source": { + "knowledge_bases": [ + "knowledge_bases_value1", + "knowledge_bases_value2", + ] + }, + "document_query_source": { + "documents": ["documents_value1", "documents_value2"] + }, + "dialogflow_query_source": {"agent": "agent_value"}, + "max_results": 1207, + "confidence_threshold": 0.2106, + "context_filter_settings": { + "drop_handoff_messages": True, + "drop_virtual_agent_messages": True, + "drop_ivr_messages": True, + }, + }, + "conversation_model_config": {"model": "model_value"}, + "conversation_process_config": {"recent_sentences_count": 2352}, + } + ], + "group_suggestion_responses": True, + }, + "end_user_suggestion_config": {}, + "message_analysis_config": { + "enable_entity_extraction": True, + "enable_sentiment_analysis": True, + }, + }, + "human_agent_handoff_config": { + "live_person_config": {"account_number": "account_number_value"}, + "salesforce_live_agent_config": { + "organization_id": "organization_id_value", + "deployment_id": "deployment_id_value", + "button_id": "button_id_value", + "endpoint_domain": "endpoint_domain_value", + }, + }, + "notification_config": {}, + "logging_config": {"enable_stackdriver_logging": True}, + "new_message_event_notification_config": {}, + "stt_config": {"speech_model_variant": 1, "model": "model_value"}, + "language_code": "language_code_value", + "time_zone": "time_zone_value", + "security_settings": "security_settings_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + time_zone="time_zone_value", + security_settings="security_settings_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_conversation_profile(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_conversation_profile.ConversationProfile) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + assert response.time_zone == "time_zone_value" + assert response.security_settings == "security_settings_value" + + +def test_create_conversation_profile_rest_required_fields( + request_type=gcd_conversation_profile.CreateConversationProfileRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_conversation_profile.ConversationProfile.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_conversation_profile(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_conversation_profile_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_conversation_profile._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "conversationProfile", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_conversation_profile_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "post_create_conversation_profile", + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "pre_create_conversation_profile", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation_profile.CreateConversationProfileRequest.pb( + gcd_conversation_profile.CreateConversationProfileRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + gcd_conversation_profile.ConversationProfile.to_json( + gcd_conversation_profile.ConversationProfile() + ) + ) + + request = gcd_conversation_profile.CreateConversationProfileRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_conversation_profile.ConversationProfile() + + client.create_conversation_profile( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_conversation_profile_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation_profile.CreateConversationProfileRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["conversation_profile"] = { + "name": "name_value", + "display_name": "display_name_value", + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "automated_agent_config": {"agent": "agent_value"}, + "human_agent_assistant_config": { + "notification_config": {"topic": "topic_value", "message_format": 1}, + "human_agent_suggestion_config": { + "feature_configs": [ + { + "suggestion_feature": {"type_": 1}, + "enable_event_based_suggestion": True, + "suggestion_trigger_settings": { + "no_small_talk": True, + "only_end_user": True, + }, + "query_config": { + "knowledge_base_query_source": { + "knowledge_bases": [ + "knowledge_bases_value1", + "knowledge_bases_value2", + ] + }, + "document_query_source": { + "documents": ["documents_value1", "documents_value2"] + }, + "dialogflow_query_source": {"agent": "agent_value"}, + "max_results": 1207, + "confidence_threshold": 0.2106, + "context_filter_settings": { + "drop_handoff_messages": True, + "drop_virtual_agent_messages": True, + "drop_ivr_messages": True, + }, + }, + "conversation_model_config": {"model": "model_value"}, + "conversation_process_config": {"recent_sentences_count": 2352}, + } + ], + "group_suggestion_responses": True, + }, + "end_user_suggestion_config": {}, + "message_analysis_config": { + "enable_entity_extraction": True, + "enable_sentiment_analysis": True, + }, + }, + "human_agent_handoff_config": { + "live_person_config": {"account_number": "account_number_value"}, + "salesforce_live_agent_config": { + "organization_id": "organization_id_value", + "deployment_id": "deployment_id_value", + "button_id": "button_id_value", + "endpoint_domain": "endpoint_domain_value", + }, + }, + "notification_config": {}, + "logging_config": {"enable_stackdriver_logging": True}, + "new_message_event_notification_config": {}, + "stt_config": {"speech_model_variant": 1, "model": "model_value"}, + "language_code": "language_code_value", + "time_zone": "time_zone_value", + "security_settings": "security_settings_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_conversation_profile(request) + + +def test_create_conversation_profile_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + conversation_profile=gcd_conversation_profile.ConversationProfile( + name="name_value" + ), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_conversation_profile(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/conversationProfiles" + % client.transport._host, + args[1], + ) + + +def test_create_conversation_profile_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_conversation_profile( + gcd_conversation_profile.CreateConversationProfileRequest(), + parent="parent_value", + conversation_profile=gcd_conversation_profile.ConversationProfile( + name="name_value" + ), + ) + + +def test_create_conversation_profile_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation_profile.UpdateConversationProfileRequest, + dict, + ], +) +def test_update_conversation_profile_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": { + "name": "projects/sample1/conversationProfiles/sample2" + } + } + request_init["conversation_profile"] = { + "name": "projects/sample1/conversationProfiles/sample2", + "display_name": "display_name_value", + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "automated_agent_config": {"agent": "agent_value"}, + "human_agent_assistant_config": { + "notification_config": {"topic": "topic_value", "message_format": 1}, + "human_agent_suggestion_config": { + "feature_configs": [ + { + "suggestion_feature": {"type_": 1}, + "enable_event_based_suggestion": True, + "suggestion_trigger_settings": { + "no_small_talk": True, + "only_end_user": True, + }, + "query_config": { + "knowledge_base_query_source": { + "knowledge_bases": [ + "knowledge_bases_value1", + "knowledge_bases_value2", + ] + }, + "document_query_source": { + "documents": ["documents_value1", "documents_value2"] + }, + "dialogflow_query_source": {"agent": "agent_value"}, + "max_results": 1207, + "confidence_threshold": 0.2106, + "context_filter_settings": { + "drop_handoff_messages": True, + "drop_virtual_agent_messages": True, + "drop_ivr_messages": True, + }, + }, + "conversation_model_config": {"model": "model_value"}, + "conversation_process_config": {"recent_sentences_count": 2352}, + } + ], + "group_suggestion_responses": True, + }, + "end_user_suggestion_config": {}, + "message_analysis_config": { + "enable_entity_extraction": True, + "enable_sentiment_analysis": True, + }, + }, + "human_agent_handoff_config": { + "live_person_config": {"account_number": "account_number_value"}, + "salesforce_live_agent_config": { + "organization_id": "organization_id_value", + "deployment_id": "deployment_id_value", + "button_id": "button_id_value", + "endpoint_domain": "endpoint_domain_value", + }, + }, + "notification_config": {}, + "logging_config": {"enable_stackdriver_logging": True}, + "new_message_event_notification_config": {}, + "stt_config": {"speech_model_variant": 1, "model": "model_value"}, + "language_code": "language_code_value", + "time_zone": "time_zone_value", + "security_settings": "security_settings_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + time_zone="time_zone_value", + security_settings="security_settings_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_conversation_profile(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_conversation_profile.ConversationProfile) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + assert response.time_zone == "time_zone_value" + assert response.security_settings == "security_settings_value" + + +def test_update_conversation_profile_rest_required_fields( + request_type=gcd_conversation_profile.UpdateConversationProfileRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_conversation_profile._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_conversation_profile.ConversationProfile.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_conversation_profile(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_conversation_profile_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_conversation_profile._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "conversationProfile", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_conversation_profile_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "post_update_conversation_profile", + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "pre_update_conversation_profile", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation_profile.UpdateConversationProfileRequest.pb( + gcd_conversation_profile.UpdateConversationProfileRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + gcd_conversation_profile.ConversationProfile.to_json( + gcd_conversation_profile.ConversationProfile() + ) + ) + + request = gcd_conversation_profile.UpdateConversationProfileRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_conversation_profile.ConversationProfile() + + client.update_conversation_profile( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_conversation_profile_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation_profile.UpdateConversationProfileRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": { + "name": "projects/sample1/conversationProfiles/sample2" + } + } + request_init["conversation_profile"] = { + "name": "projects/sample1/conversationProfiles/sample2", + "display_name": "display_name_value", + "create_time": {"seconds": 751, "nanos": 543}, + "update_time": {}, + "automated_agent_config": {"agent": "agent_value"}, + "human_agent_assistant_config": { + "notification_config": {"topic": "topic_value", "message_format": 1}, + "human_agent_suggestion_config": { + "feature_configs": [ + { + "suggestion_feature": {"type_": 1}, + "enable_event_based_suggestion": True, + "suggestion_trigger_settings": { + "no_small_talk": True, + "only_end_user": True, + }, + "query_config": { + "knowledge_base_query_source": { + "knowledge_bases": [ + "knowledge_bases_value1", + "knowledge_bases_value2", + ] + }, + "document_query_source": { + "documents": ["documents_value1", "documents_value2"] + }, + "dialogflow_query_source": {"agent": "agent_value"}, + "max_results": 1207, + "confidence_threshold": 0.2106, + "context_filter_settings": { + "drop_handoff_messages": True, + "drop_virtual_agent_messages": True, + "drop_ivr_messages": True, + }, + }, + "conversation_model_config": {"model": "model_value"}, + "conversation_process_config": {"recent_sentences_count": 2352}, + } + ], + "group_suggestion_responses": True, + }, + "end_user_suggestion_config": {}, + "message_analysis_config": { + "enable_entity_extraction": True, + "enable_sentiment_analysis": True, + }, + }, + "human_agent_handoff_config": { + "live_person_config": {"account_number": "account_number_value"}, + "salesforce_live_agent_config": { + "organization_id": "organization_id_value", + "deployment_id": "deployment_id_value", + "button_id": "button_id_value", + "endpoint_domain": "endpoint_domain_value", + }, + }, + "notification_config": {}, + "logging_config": {"enable_stackdriver_logging": True}, + "new_message_event_notification_config": {}, + "stt_config": {"speech_model_variant": 1, "model": "model_value"}, + "language_code": "language_code_value", + "time_zone": "time_zone_value", + "security_settings": "security_settings_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_conversation_profile(request) + + +def test_update_conversation_profile_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation_profile.ConversationProfile() + + # get arguments that satisfy an http rule for this method + sample_request = { + "conversation_profile": { + "name": "projects/sample1/conversationProfiles/sample2" + } + } + + # get truthy value for each flattened field + mock_args = dict( + conversation_profile=gcd_conversation_profile.ConversationProfile( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation_profile.ConversationProfile.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_conversation_profile(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{conversation_profile.name=projects/*/conversationProfiles/*}" + % client.transport._host, + args[1], + ) + + +def test_update_conversation_profile_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_conversation_profile( + gcd_conversation_profile.UpdateConversationProfileRequest(), + conversation_profile=gcd_conversation_profile.ConversationProfile( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_conversation_profile_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation_profile.DeleteConversationProfileRequest, + dict, + ], +) +def test_delete_conversation_profile_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationProfiles/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_conversation_profile(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_conversation_profile_rest_required_fields( + request_type=conversation_profile.DeleteConversationProfileRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_conversation_profile._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_conversation_profile(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_conversation_profile_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_conversation_profile._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_conversation_profile_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "pre_delete_conversation_profile", + ) as pre: + pre.assert_not_called() + pb_message = conversation_profile.DeleteConversationProfileRequest.pb( + conversation_profile.DeleteConversationProfileRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = conversation_profile.DeleteConversationProfileRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_conversation_profile( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_conversation_profile_rest_bad_request( + transport: str = "rest", + request_type=conversation_profile.DeleteConversationProfileRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversationProfiles/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_conversation_profile(request) + + +def test_delete_conversation_profile_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/conversationProfiles/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_conversation_profile(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/conversationProfiles/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_conversation_profile_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_conversation_profile( + conversation_profile.DeleteConversationProfileRequest(), + name="name_value", + ) + + +def test_delete_conversation_profile_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation_profile.SetSuggestionFeatureConfigRequest, + dict, + ], +) +def test_set_suggestion_feature_config_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.set_suggestion_feature_config(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_set_suggestion_feature_config_rest_required_fields( + request_type=gcd_conversation_profile.SetSuggestionFeatureConfigRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["conversation_profile"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).set_suggestion_feature_config._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["conversationProfile"] = "conversation_profile_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).set_suggestion_feature_config._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "conversationProfile" in jsonified_request + assert jsonified_request["conversationProfile"] == "conversation_profile_value" + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.set_suggestion_feature_config(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_set_suggestion_feature_config_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.set_suggestion_feature_config._get_unset_required_fields( + {} + ) + assert set(unset_fields) == ( + set(()) + & set( + ( + "conversationProfile", + "participantRole", + "suggestionFeatureConfig", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_set_suggestion_feature_config_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "post_set_suggestion_feature_config", + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "pre_set_suggestion_feature_config", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation_profile.SetSuggestionFeatureConfigRequest.pb( + gcd_conversation_profile.SetSuggestionFeatureConfigRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = gcd_conversation_profile.SetSuggestionFeatureConfigRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.set_suggestion_feature_config( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_set_suggestion_feature_config_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation_profile.SetSuggestionFeatureConfigRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.set_suggestion_feature_config(request) + + +def test_set_suggestion_feature_config_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + + # get truthy value for each flattened field + mock_args = dict( + conversation_profile="conversation_profile_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.set_suggestion_feature_config(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{conversation_profile=projects/*/conversationProfiles/*}:setSuggestionFeatureConfig" + % client.transport._host, + args[1], + ) + + +def test_set_suggestion_feature_config_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.set_suggestion_feature_config( + gcd_conversation_profile.SetSuggestionFeatureConfigRequest(), + conversation_profile="conversation_profile_value", + ) + + +def test_set_suggestion_feature_config_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, + dict, + ], +) +def test_clear_suggestion_feature_config_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.clear_suggestion_feature_config(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_clear_suggestion_feature_config_rest_required_fields( + request_type=gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, +): + transport_class = transports.ConversationProfilesRestTransport + + request_init = {} + request_init["conversation_profile"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).clear_suggestion_feature_config._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["conversationProfile"] = "conversation_profile_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).clear_suggestion_feature_config._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "conversationProfile" in jsonified_request + assert jsonified_request["conversationProfile"] == "conversation_profile_value" + + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.clear_suggestion_feature_config(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_clear_suggestion_feature_config_rest_unset_required_fields(): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.clear_suggestion_feature_config._get_unset_required_fields( + {} + ) + assert set(unset_fields) == ( + set(()) + & set( + ( + "conversationProfile", + "participantRole", + "suggestionFeatureType", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_clear_suggestion_feature_config_rest_interceptors(null_interceptor): + transport = transports.ConversationProfilesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationProfilesRestInterceptor(), + ) + client = ConversationProfilesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "post_clear_suggestion_feature_config", + ) as post, mock.patch.object( + transports.ConversationProfilesRestInterceptor, + "pre_clear_suggestion_feature_config", + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation_profile.ClearSuggestionFeatureConfigRequest.pb( + gcd_conversation_profile.ClearSuggestionFeatureConfigRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = gcd_conversation_profile.ClearSuggestionFeatureConfigRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.clear_suggestion_feature_config( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_clear_suggestion_feature_config_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation_profile.ClearSuggestionFeatureConfigRequest, +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.clear_suggestion_feature_config(request) + + +def test_clear_suggestion_feature_config_rest_flattened(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "conversation_profile": "projects/sample1/conversationProfiles/sample2" + } + + # get truthy value for each flattened field + mock_args = dict( + conversation_profile="conversation_profile_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.clear_suggestion_feature_config(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{conversation_profile=projects/*/conversationProfiles/*}:clearSuggestionFeatureConfig" + % client.transport._host, + args[1], + ) + + +def test_clear_suggestion_feature_config_rest_flattened_error(transport: str = "rest"): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.clear_suggestion_feature_config( + gcd_conversation_profile.ClearSuggestionFeatureConfigRequest(), + conversation_profile="conversation_profile_value", + ) + + +def test_clear_suggestion_feature_config_rest_error(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationProfilesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationProfilesClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationProfilesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationProfilesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ConversationProfilesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationProfilesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ConversationProfilesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ConversationProfilesGrpcTransport, + transports.ConversationProfilesGrpcAsyncIOTransport, + transports.ConversationProfilesRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = ConversationProfilesClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ConversationProfilesGrpcTransport, + ) + + +def test_conversation_profiles_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ConversationProfilesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_conversation_profiles_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2beta1.services.conversation_profiles.transports.ConversationProfilesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ConversationProfilesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_conversation_profiles", + "get_conversation_profile", + "create_conversation_profile", + "update_conversation_profile", + "delete_conversation_profile", + "set_suggestion_feature_config", + "clear_suggestion_feature_config", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] for r in remainder: with pytest.raises(NotImplementedError): getattr(transport, r)() @@ -2962,6 +5327,7 @@ def test_conversation_profiles_transport_auth_adc(transport_class): [ transports.ConversationProfilesGrpcTransport, transports.ConversationProfilesGrpcAsyncIOTransport, + transports.ConversationProfilesRestTransport, ], ) def test_conversation_profiles_transport_auth_gdch_credentials(transport_class): @@ -3064,11 +5430,40 @@ def test_conversation_profiles_grpc_transport_client_cert_source_for_mtls( ) +def test_conversation_profiles_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.ConversationProfilesRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_conversation_profiles_rest_lro_client(): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversation_profiles_host_no_port(transport_name): @@ -3079,7 +5474,11 @@ def test_conversation_profiles_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3087,6 +5486,7 @@ def test_conversation_profiles_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversation_profiles_host_with_port(transport_name): @@ -3097,7 +5497,51 @@ def test_conversation_profiles_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_conversation_profiles_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ConversationProfilesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ConversationProfilesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_conversation_profiles._session + session2 = client2.transport.list_conversation_profiles._session + assert session1 != session2 + session1 = client1.transport.get_conversation_profile._session + session2 = client2.transport.get_conversation_profile._session + assert session1 != session2 + session1 = client1.transport.create_conversation_profile._session + session2 = client2.transport.create_conversation_profile._session + assert session1 != session2 + session1 = client1.transport.update_conversation_profile._session + session2 = client2.transport.update_conversation_profile._session + assert session1 != session2 + session1 = client1.transport.delete_conversation_profile._session + session2 = client2.transport.delete_conversation_profile._session + assert session1 != session2 + session1 = client1.transport.set_suggestion_feature_config._session + session2 = client2.transport.set_suggestion_feature_config._session + assert session1 != session2 + session1 = client1.transport.clear_suggestion_feature_config._session + session2 = client2.transport.clear_suggestion_feature_config._session + assert session1 != session2 def test_conversation_profiles_grpc_transport_channel(): @@ -3550,6 +5994,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ConversationProfilesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ConversationProfilesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4271,6 +7001,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4288,6 +7019,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_conversations.py b/tests/unit/gapic/dialogflow_v2beta1/test_conversations.py index 1ec9e2c65..23e1177b9 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_conversations.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_conversations.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -33,6 +35,7 @@ from google.cloud.location import locations_pb2 from google.longrunning import operations_pb2 from google.oauth2 import service_account +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore import grpc @@ -40,6 +43,8 @@ from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.conversations import ( ConversationsAsyncClient, @@ -101,6 +106,7 @@ def test__get_default_mtls_endpoint(): [ (ConversationsClient, "grpc"), (ConversationsAsyncClient, "grpc_asyncio"), + (ConversationsClient, "rest"), ], ) def test_conversations_client_from_service_account_info(client_class, transport_name): @@ -114,7 +120,11 @@ def test_conversations_client_from_service_account_info(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -122,6 +132,7 @@ def test_conversations_client_from_service_account_info(client_class, transport_ [ (transports.ConversationsGrpcTransport, "grpc"), (transports.ConversationsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ConversationsRestTransport, "rest"), ], ) def test_conversations_client_service_account_always_use_jwt( @@ -147,6 +158,7 @@ def test_conversations_client_service_account_always_use_jwt( [ (ConversationsClient, "grpc"), (ConversationsAsyncClient, "grpc_asyncio"), + (ConversationsClient, "rest"), ], ) def test_conversations_client_from_service_account_file(client_class, transport_name): @@ -167,13 +179,18 @@ def test_conversations_client_from_service_account_file(client_class, transport_ assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_conversations_client_get_transport_class(): transport = ConversationsClient.get_transport_class() available_transports = [ transports.ConversationsGrpcTransport, + transports.ConversationsRestTransport, ] assert transport in available_transports @@ -190,6 +207,7 @@ def test_conversations_client_get_transport_class(): transports.ConversationsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ConversationsClient, transports.ConversationsRestTransport, "rest"), ], ) @mock.patch.object( @@ -335,6 +353,8 @@ def test_conversations_client_client_options( "grpc_asyncio", "false", ), + (ConversationsClient, transports.ConversationsRestTransport, "rest", "true"), + (ConversationsClient, transports.ConversationsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -534,6 +554,7 @@ def test_conversations_client_get_mtls_endpoint_and_cert_source(client_class): transports.ConversationsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ConversationsClient, transports.ConversationsRestTransport, "rest"), ], ) def test_conversations_client_client_options_scopes( @@ -574,6 +595,7 @@ def test_conversations_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (ConversationsClient, transports.ConversationsRestTransport, "rest", None), ], ) def test_conversations_client_client_options_credentials_file( @@ -2847,199 +2869,2304 @@ async def test_suggest_conversation_summary_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ConversationsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation.CreateConversationRequest, + dict, + ], +) +def test_create_conversation_rest(request_type): + client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = ConversationsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["conversation"] = { + "name": "name_value", + "lifecycle_state": 1, + "conversation_profile": "conversation_profile_value", + "phone_number": {"phone_number": "phone_number_value"}, + "conversation_stage": 1, + "start_time": {"seconds": 751, "nanos": 543}, + "end_time": {}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.Conversation( + name="name_value", + lifecycle_state=gcd_conversation.Conversation.LifecycleState.IN_PROGRESS, + conversation_profile="conversation_profile_value", + conversation_stage=gcd_conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE, ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ConversationsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_conversation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_conversation.Conversation) + assert response.name == "name_value" + assert ( + response.lifecycle_state + == gcd_conversation.Conversation.LifecycleState.IN_PROGRESS ) - with pytest.raises(ValueError): - client = ConversationsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + assert response.conversation_profile == "conversation_profile_value" + assert ( + response.conversation_stage + == gcd_conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE + ) + + +def test_create_conversation_rest_required_fields( + request_type=gcd_conversation.CreateConversationRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.ConversationsGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("conversation_id",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.Conversation() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_conversation(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_conversation_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationsClient( - client_options=options, - transport=transport, - ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ConversationsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + unset_fields = transport.create_conversation._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("conversationId",)) + & set( + ( + "parent", + "conversation", + ) ) + ) - # It is an error to provide scopes and a transport instance. - transport = transports.ConversationsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_conversation_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), ) - with pytest.raises(ValueError): - client = ConversationsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_create_conversation" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_create_conversation" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation.CreateConversationRequest.pb( + gcd_conversation.CreateConversationRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_conversation.Conversation.to_json( + gcd_conversation.Conversation() ) + request = gcd_conversation.CreateConversationRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_conversation.Conversation() -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationsGrpcTransport( + client.create_conversation( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_conversation_rest_bad_request( + transport: str = "rest", request_type=gcd_conversation.CreateConversationRequest +): + client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = ConversationsClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["conversation"] = { + "name": "name_value", + "lifecycle_state": 1, + "conversation_profile": "conversation_profile_value", + "phone_number": {"phone_number": "phone_number_value"}, + "conversation_stage": 1, + "start_time": {"seconds": 751, "nanos": 543}, + "end_time": {}, + } + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ConversationsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_conversation(request) + + +def test_create_conversation_rest_flattened(): + client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.ConversationsGrpcAsyncIOTransport( + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.Conversation() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + conversation=gcd_conversation.Conversation(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_conversation(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/conversations" % client.transport._host, + args[1], + ) + + +def test_create_conversation_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_conversation( + gcd_conversation.CreateConversationRequest(), + parent="parent_value", + conversation=gcd_conversation.Conversation(name="name_value"), + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.ConversationsGrpcTransport, - transports.ConversationsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() +def test_create_conversation_rest_error(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + conversation.ListConversationsRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = ConversationsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name - - -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. +def test_list_conversations_rest(request_type): client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.ConversationsGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) -def test_conversations_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ConversationsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.ListConversationsResponse( + next_page_token="next_page_token_value", ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.ListConversationsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_conversations_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2beta1.services.conversations.transports.ConversationsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ConversationsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_conversations(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "create_conversation", - "list_conversations", - "get_conversation", - "complete_conversation", - "batch_create_messages", - "list_messages", - "suggest_conversation_summary", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListConversationsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_conversations_rest_required_fields( + request_type=conversation.ListConversationsRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversations._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + # verify required fields with default values are now present -def test_conversations_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.dialogflow_v2beta1.services.conversations.transports.ConversationsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.ConversationsTransport( - credentials_file="credentials.json", - quota_project_id="octopus", - ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_conversations._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "filter", + "page_size", + "page_token", ) + ) + jsonified_request.update(unset_fields) + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" -def test_conversations_base_transport_with_adc(): - # Test the default credentials are used if credentials and credentials_file are None. - with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation.ListConversationsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation.ListConversationsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_conversations(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_conversations_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_conversations._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_conversations_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), + ) + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_list_conversations" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_list_conversations" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation.ListConversationsRequest.pb( + conversation.ListConversationsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation.ListConversationsResponse.to_json( + conversation.ListConversationsResponse() + ) + + request = conversation.ListConversationsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation.ListConversationsResponse() + + client.list_conversations( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_conversations_rest_bad_request( + transport: str = "rest", request_type=conversation.ListConversationsRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_conversations(request) + + +def test_list_conversations_rest_flattened(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.ListConversationsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.ListConversationsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_conversations(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/conversations" % client.transport._host, + args[1], + ) + + +def test_list_conversations_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_conversations( + conversation.ListConversationsRequest(), + parent="parent_value", + ) + + +def test_list_conversations_rest_pager(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + conversation.ListConversationsResponse( + conversations=[ + conversation.Conversation(), + conversation.Conversation(), + conversation.Conversation(), + ], + next_page_token="abc", + ), + conversation.ListConversationsResponse( + conversations=[], + next_page_token="def", + ), + conversation.ListConversationsResponse( + conversations=[ + conversation.Conversation(), + ], + next_page_token="ghi", + ), + conversation.ListConversationsResponse( + conversations=[ + conversation.Conversation(), + conversation.Conversation(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + conversation.ListConversationsResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1"} + + pager = client.list_conversations(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, conversation.Conversation) for i in results) + + pages = list(client.list_conversations(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + conversation.GetConversationRequest, + dict, + ], +) +def test_get_conversation_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation( + name="name_value", + lifecycle_state=conversation.Conversation.LifecycleState.IN_PROGRESS, + conversation_profile="conversation_profile_value", + conversation_stage=conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_conversation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, conversation.Conversation) + assert response.name == "name_value" + assert ( + response.lifecycle_state == conversation.Conversation.LifecycleState.IN_PROGRESS + ) + assert response.conversation_profile == "conversation_profile_value" + assert ( + response.conversation_stage + == conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE + ) + + +def test_get_conversation_rest_required_fields( + request_type=conversation.GetConversationRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_conversation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_conversation(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_conversation_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_conversation._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_conversation_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), + ) + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_get_conversation" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_get_conversation" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation.GetConversationRequest.pb( + conversation.GetConversationRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation.Conversation.to_json( + conversation.Conversation() + ) + + request = conversation.GetConversationRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation.Conversation() + + client.get_conversation( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_conversation_rest_bad_request( + transport: str = "rest", request_type=conversation.GetConversationRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_conversation(request) + + +def test_get_conversation_rest_flattened(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_conversation(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/conversations/*}" % client.transport._host, + args[1], + ) + + +def test_get_conversation_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_conversation( + conversation.GetConversationRequest(), + name="name_value", + ) + + +def test_get_conversation_rest_error(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation.CompleteConversationRequest, + dict, + ], +) +def test_complete_conversation_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation( + name="name_value", + lifecycle_state=conversation.Conversation.LifecycleState.IN_PROGRESS, + conversation_profile="conversation_profile_value", + conversation_stage=conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.complete_conversation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, conversation.Conversation) + assert response.name == "name_value" + assert ( + response.lifecycle_state == conversation.Conversation.LifecycleState.IN_PROGRESS + ) + assert response.conversation_profile == "conversation_profile_value" + assert ( + response.conversation_stage + == conversation.Conversation.ConversationStage.VIRTUAL_AGENT_STAGE + ) + + +def test_complete_conversation_rest_required_fields( + request_type=conversation.CompleteConversationRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).complete_conversation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).complete_conversation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.complete_conversation(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_complete_conversation_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.complete_conversation._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_complete_conversation_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), + ) + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_complete_conversation" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_complete_conversation" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation.CompleteConversationRequest.pb( + conversation.CompleteConversationRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation.Conversation.to_json( + conversation.Conversation() + ) + + request = conversation.CompleteConversationRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation.Conversation() + + client.complete_conversation( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_complete_conversation_rest_bad_request( + transport: str = "rest", request_type=conversation.CompleteConversationRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.complete_conversation(request) + + +def test_complete_conversation_rest_flattened(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.Conversation() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.complete_conversation(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/conversations/*}:complete" + % client.transport._host, + args[1], + ) + + +def test_complete_conversation_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.complete_conversation( + conversation.CompleteConversationRequest(), + name="name_value", + ) + + +def test_complete_conversation_rest_error(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation.BatchCreateMessagesRequest, + dict, + ], +) +def test_batch_create_messages_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.BatchCreateMessagesResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.BatchCreateMessagesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_create_messages(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, conversation.BatchCreateMessagesResponse) + + +def test_batch_create_messages_rest_required_fields( + request_type=conversation.BatchCreateMessagesRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_create_messages._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_create_messages._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation.BatchCreateMessagesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation.BatchCreateMessagesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_create_messages(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_create_messages_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_create_messages._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "requests", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_create_messages_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), + ) + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_batch_create_messages" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_batch_create_messages" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation.BatchCreateMessagesRequest.pb( + conversation.BatchCreateMessagesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation.BatchCreateMessagesResponse.to_json( + conversation.BatchCreateMessagesResponse() + ) + + request = conversation.BatchCreateMessagesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation.BatchCreateMessagesResponse() + + client.batch_create_messages( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_create_messages_rest_bad_request( + transport: str = "rest", request_type=conversation.BatchCreateMessagesRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_create_messages(request) + + +def test_batch_create_messages_rest_flattened(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.BatchCreateMessagesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.BatchCreateMessagesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_create_messages(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/conversations/*}/messages:batchCreate" + % client.transport._host, + args[1], + ) + + +def test_batch_create_messages_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_create_messages( + conversation.BatchCreateMessagesRequest(), + parent="parent_value", + ) + + +def test_batch_create_messages_rest_error(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation.ListMessagesRequest, + dict, + ], +) +def test_list_messages_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.ListMessagesResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.ListMessagesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_messages(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListMessagesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_messages_rest_required_fields( + request_type=conversation.ListMessagesRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_messages._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_messages._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "filter", + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = conversation.ListMessagesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = conversation.ListMessagesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_messages(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_messages_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_messages._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_messages_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), + ) + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_list_messages" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_list_messages" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = conversation.ListMessagesRequest.pb( + conversation.ListMessagesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = conversation.ListMessagesResponse.to_json( + conversation.ListMessagesResponse() + ) + + request = conversation.ListMessagesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = conversation.ListMessagesResponse() + + client.list_messages( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_messages_rest_bad_request( + transport: str = "rest", request_type=conversation.ListMessagesRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_messages(request) + + +def test_list_messages_rest_flattened(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = conversation.ListMessagesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = conversation.ListMessagesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_messages(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/conversations/*}/messages" + % client.transport._host, + args[1], + ) + + +def test_list_messages_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_messages( + conversation.ListMessagesRequest(), + parent="parent_value", + ) + + +def test_list_messages_rest_pager(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + conversation.ListMessagesResponse( + messages=[ + participant.Message(), + participant.Message(), + participant.Message(), + ], + next_page_token="abc", + ), + conversation.ListMessagesResponse( + messages=[], + next_page_token="def", + ), + conversation.ListMessagesResponse( + messages=[ + participant.Message(), + ], + next_page_token="ghi", + ), + conversation.ListMessagesResponse( + messages=[ + participant.Message(), + participant.Message(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(conversation.ListMessagesResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/conversations/sample2"} + + pager = client.list_messages(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, participant.Message) for i in results) + + pages = list(client.list_messages(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_conversation.SuggestConversationSummaryRequest, + dict, + ], +) +def test_suggest_conversation_summary_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"conversation": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.SuggestConversationSummaryResponse( + latest_message="latest_message_value", + context_size=1311, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation.SuggestConversationSummaryResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.suggest_conversation_summary(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_conversation.SuggestConversationSummaryResponse) + assert response.latest_message == "latest_message_value" + assert response.context_size == 1311 + + +def test_suggest_conversation_summary_rest_required_fields( + request_type=gcd_conversation.SuggestConversationSummaryRequest, +): + transport_class = transports.ConversationsRestTransport + + request_init = {} + request_init["conversation"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_conversation_summary._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["conversation"] = "conversation_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_conversation_summary._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "conversation" in jsonified_request + assert jsonified_request["conversation"] == "conversation_value" + + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.SuggestConversationSummaryResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_conversation.SuggestConversationSummaryResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.suggest_conversation_summary(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_suggest_conversation_summary_rest_unset_required_fields(): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.suggest_conversation_summary._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("conversation",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_suggest_conversation_summary_rest_interceptors(null_interceptor): + transport = transports.ConversationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ConversationsRestInterceptor(), + ) + client = ConversationsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ConversationsRestInterceptor, "post_suggest_conversation_summary" + ) as post, mock.patch.object( + transports.ConversationsRestInterceptor, "pre_suggest_conversation_summary" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_conversation.SuggestConversationSummaryRequest.pb( + gcd_conversation.SuggestConversationSummaryRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + gcd_conversation.SuggestConversationSummaryResponse.to_json( + gcd_conversation.SuggestConversationSummaryResponse() + ) + ) + + request = gcd_conversation.SuggestConversationSummaryRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_conversation.SuggestConversationSummaryResponse() + + client.suggest_conversation_summary( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_suggest_conversation_summary_rest_bad_request( + transport: str = "rest", + request_type=gcd_conversation.SuggestConversationSummaryRequest, +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"conversation": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.suggest_conversation_summary(request) + + +def test_suggest_conversation_summary_rest_flattened(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_conversation.SuggestConversationSummaryResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"conversation": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + conversation="conversation_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_conversation.SuggestConversationSummaryResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.suggest_conversation_summary(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{conversation=projects/*/conversations/*}/suggestions:suggestConversationSummary" + % client.transport._host, + args[1], + ) + + +def test_suggest_conversation_summary_rest_flattened_error(transport: str = "rest"): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.suggest_conversation_summary( + gcd_conversation.SuggestConversationSummaryRequest(), + conversation="conversation_value", + ) + + +def test_suggest_conversation_summary_rest_error(): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ConversationsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ConversationsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ConversationsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ConversationsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ConversationsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ConversationsGrpcTransport, + transports.ConversationsGrpcAsyncIOTransport, + transports.ConversationsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = ConversationsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ConversationsGrpcTransport, + ) + + +def test_conversations_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ConversationsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_conversations_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2beta1.services.conversations.transports.ConversationsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ConversationsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "create_conversation", + "list_conversations", + "get_conversation", + "complete_conversation", + "batch_create_messages", + "list_messages", + "suggest_conversation_summary", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_conversations_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.dialogflow_v2beta1.services.conversations.transports.ConversationsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.ConversationsTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_conversations_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( "google.cloud.dialogflow_v2beta1.services.conversations.transports.ConversationsTransport._prep_wrapped_messages" ) as Transport: Transport.return_value = None @@ -3091,6 +5218,7 @@ def test_conversations_transport_auth_adc(transport_class): [ transports.ConversationsGrpcTransport, transports.ConversationsGrpcAsyncIOTransport, + transports.ConversationsRestTransport, ], ) def test_conversations_transport_auth_gdch_credentials(transport_class): @@ -3191,11 +5319,23 @@ def test_conversations_grpc_transport_client_cert_source_for_mtls(transport_clas ) +def test_conversations_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.ConversationsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversations_host_no_port(transport_name): @@ -3206,7 +5346,11 @@ def test_conversations_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3214,6 +5358,7 @@ def test_conversations_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_conversations_host_with_port(transport_name): @@ -3224,7 +5369,51 @@ def test_conversations_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_conversations_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ConversationsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ConversationsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_conversation._session + session2 = client2.transport.create_conversation._session + assert session1 != session2 + session1 = client1.transport.list_conversations._session + session2 = client2.transport.list_conversations._session + assert session1 != session2 + session1 = client1.transport.get_conversation._session + session2 = client2.transport.get_conversation._session + assert session1 != session2 + session1 = client1.transport.complete_conversation._session + session2 = client2.transport.complete_conversation._session + assert session1 != session2 + session1 = client1.transport.batch_create_messages._session + session2 = client2.transport.batch_create_messages._session + assert session1 != session2 + session1 = client1.transport.list_messages._session + session2 = client2.transport.list_messages._session + assert session1 != session2 + session1 = client1.transport.suggest_conversation_summary._session + session2 = client2.transport.suggest_conversation_summary._session + assert session1 != session2 def test_conversations_grpc_transport_channel(): @@ -3590,6 +5779,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ConversationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ConversationsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4307,6 +6782,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4324,6 +6800,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_documents.py b/tests/unit/gapic/dialogflow_v2beta1/test_documents.py index b09b83145..7ed3d9bc0 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_documents.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_documents.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -45,6 +47,7 @@ from google.protobuf import any_pb2 # type: ignore from google.protobuf import empty_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore from google.rpc import status_pb2 # type: ignore import grpc @@ -52,6 +55,8 @@ from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.documents import ( DocumentsAsyncClient, @@ -108,6 +113,7 @@ def test__get_default_mtls_endpoint(): [ (DocumentsClient, "grpc"), (DocumentsAsyncClient, "grpc_asyncio"), + (DocumentsClient, "rest"), ], ) def test_documents_client_from_service_account_info(client_class, transport_name): @@ -121,7 +127,11 @@ def test_documents_client_from_service_account_info(client_class, transport_name assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -129,6 +139,7 @@ def test_documents_client_from_service_account_info(client_class, transport_name [ (transports.DocumentsGrpcTransport, "grpc"), (transports.DocumentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.DocumentsRestTransport, "rest"), ], ) def test_documents_client_service_account_always_use_jwt( @@ -154,6 +165,7 @@ def test_documents_client_service_account_always_use_jwt( [ (DocumentsClient, "grpc"), (DocumentsAsyncClient, "grpc_asyncio"), + (DocumentsClient, "rest"), ], ) def test_documents_client_from_service_account_file(client_class, transport_name): @@ -174,13 +186,18 @@ def test_documents_client_from_service_account_file(client_class, transport_name assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_documents_client_get_transport_class(): transport = DocumentsClient.get_transport_class() available_transports = [ transports.DocumentsGrpcTransport, + transports.DocumentsRestTransport, ] assert transport in available_transports @@ -197,6 +214,7 @@ def test_documents_client_get_transport_class(): transports.DocumentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (DocumentsClient, transports.DocumentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -338,6 +356,8 @@ def test_documents_client_client_options(client_class, transport_class, transpor "grpc_asyncio", "false", ), + (DocumentsClient, transports.DocumentsRestTransport, "rest", "true"), + (DocumentsClient, transports.DocumentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -531,6 +551,7 @@ def test_documents_client_get_mtls_endpoint_and_cert_source(client_class): transports.DocumentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (DocumentsClient, transports.DocumentsRestTransport, "rest"), ], ) def test_documents_client_client_options_scopes( @@ -566,6 +587,7 @@ def test_documents_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (DocumentsClient, transports.DocumentsRestTransport, "rest", None), ], ) def test_documents_client_client_options_credentials_file( @@ -2417,213 +2439,2210 @@ async def test_reload_document_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.DocumentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + document.ListDocumentsRequest, + dict, + ], +) +def test_list_documents_rest(request_type): + client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = DocumentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.DocumentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = DocumentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.DocumentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = DocumentsClient( - client_options=options, - transport=transport, + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = document.ListDocumentsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = DocumentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = document.ListDocumentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.DocumentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_documents(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListDocumentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_documents_rest_required_fields( + request_type=document.ListDocumentsRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - with pytest.raises(ValueError): - client = DocumentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_documents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_documents._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "filter", + "page_size", + "page_token", ) + ) + jsonified_request.update(unset_fields) + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.DocumentsGrpcTransport( + client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = DocumentsClient(transport=transport) - assert client.transport is transport + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = document.ListDocumentsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + response_value = Response() + response_value.status_code = 200 -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.DocumentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + pb_return_value = document.ListDocumentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_documents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_documents_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - channel = transport.grpc_channel - assert channel - transport = transports.DocumentsGrpcAsyncIOTransport( + unset_fields = transport.list_documents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_documents_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), ) - channel = transport.grpc_channel - assert channel + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.DocumentsRestInterceptor, "post_list_documents" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_list_documents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = document.ListDocumentsRequest.pb(document.ListDocumentsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = document.ListDocumentsResponse.to_json( + document.ListDocumentsResponse() + ) + request = document.ListDocumentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = document.ListDocumentsResponse() -@pytest.mark.parametrize( - "transport_class", - [ - transports.DocumentsGrpcTransport, - transports.DocumentsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + client.list_documents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + pre.assert_called_once() + post.assert_called_once() -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = DocumentsClient.get_transport_class(transport_name)( + +def test_list_documents_rest_bad_request( + transport: str = "rest", request_type=document.ListDocumentsRequest +): + client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_documents(request) + + +def test_list_documents_rest_flattened(): client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.DocumentsGrpcTransport, + transport="rest", ) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = document.ListDocumentsResponse() -def test_documents_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.DocumentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/knowledgeBases/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", ) + mock_args.update(sample_request) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = document.ListDocumentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value -def test_documents_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2beta1.services.documents.transports.DocumentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.DocumentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_documents(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/knowledgeBases/*}/documents" + % client.transport._host, + args[1], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_documents", - "get_document", - "create_document", - "import_documents", - "delete_document", - "update_document", - "reload_document", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() +def test_list_documents_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_documents( + document.ListDocumentsRequest(), + parent="parent_value", + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() +def test_list_documents_rest_pager(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) -def test_documents_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.dialogflow_v2beta1.services.documents.transports.DocumentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.DocumentsTransport( - credentials_file="credentials.json", - quota_project_id="octopus", - ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + document.ListDocumentsResponse( + documents=[ + document.Document(), + document.Document(), + document.Document(), + ], + next_page_token="abc", + ), + document.ListDocumentsResponse( + documents=[], + next_page_token="def", + ), + document.ListDocumentsResponse( + documents=[ + document.Document(), + ], + next_page_token="ghi", + ), + document.ListDocumentsResponse( + documents=[ + document.Document(), + document.Document(), + ], ), - quota_project_id="octopus", ) + # Two responses for two calls + response = response + response + # Wrap the values into proper Response objs + response = tuple(document.ListDocumentsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values -def test_documents_base_transport_with_adc(): - # Test the default credentials are used if credentials and credentials_file are None. - with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( - "google.cloud.dialogflow_v2beta1.services.documents.transports.DocumentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.DocumentsTransport() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1/knowledgeBases/sample2"} + pager = client.list_documents(request=sample_request) -def test_documents_auth_adc(): + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, document.Document) for i in results) + + pages = list(client.list_documents(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + document.GetDocumentRequest, + dict, + ], +) +def test_get_document_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = document.Document( + name="name_value", + display_name="display_name_value", + mime_type="mime_type_value", + knowledge_types=[document.Document.KnowledgeType.FAQ], + enable_auto_reload=True, + state=document.Document.State.CREATING, + content_uri="content_uri_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = document.Document.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_document(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, document.Document) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.mime_type == "mime_type_value" + assert response.knowledge_types == [document.Document.KnowledgeType.FAQ] + assert response.enable_auto_reload is True + assert response.state == document.Document.State.CREATING + + +def test_get_document_rest_required_fields(request_type=document.GetDocumentRequest): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = document.Document() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = document.Document.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_document(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_document_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_document._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_document_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.DocumentsRestInterceptor, "post_get_document" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_get_document" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = document.GetDocumentRequest.pb(document.GetDocumentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = document.Document.to_json(document.Document()) + + request = document.GetDocumentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = document.Document() + + client.get_document( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_document_rest_bad_request( + transport: str = "rest", request_type=document.GetDocumentRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_document(request) + + +def test_get_document_rest_flattened(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = document.Document() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = document.Document.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_document(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/knowledgeBases/*/documents/*}" + % client.transport._host, + args[1], + ) + + +def test_get_document_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_document( + document.GetDocumentRequest(), + name="name_value", + ) + + +def test_get_document_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_document.CreateDocumentRequest, + dict, + ], +) +def test_create_document_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request_init["document"] = { + "name": "name_value", + "display_name": "display_name_value", + "mime_type": "mime_type_value", + "knowledge_types": [1], + "content_uri": "content_uri_value", + "content": "content_value", + "raw_content": b"raw_content_blob", + "enable_auto_reload": True, + "latest_reload_status": { + "time": {"seconds": 751, "nanos": 543}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + "metadata": {}, + "state": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_document(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_create_document_rest_required_fields( + request_type=gcd_document.CreateDocumentRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_document._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("import_gcs_custom_metadata",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_document(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_document_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_document._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("importGcsCustomMetadata",)) + & set( + ( + "parent", + "document", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_document_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.DocumentsRestInterceptor, "post_create_document" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_create_document" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_document.CreateDocumentRequest.pb( + gcd_document.CreateDocumentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = gcd_document.CreateDocumentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.create_document( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_document_rest_bad_request( + transport: str = "rest", request_type=gcd_document.CreateDocumentRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request_init["document"] = { + "name": "name_value", + "display_name": "display_name_value", + "mime_type": "mime_type_value", + "knowledge_types": [1], + "content_uri": "content_uri_value", + "content": "content_value", + "raw_content": b"raw_content_blob", + "enable_auto_reload": True, + "latest_reload_status": { + "time": {"seconds": 751, "nanos": 543}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + "metadata": {}, + "state": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_document(request) + + +def test_create_document_rest_flattened(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/knowledgeBases/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + document=gcd_document.Document(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_document(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/knowledgeBases/*}/documents" + % client.transport._host, + args[1], + ) + + +def test_create_document_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_document( + gcd_document.CreateDocumentRequest(), + parent="parent_value", + document=gcd_document.Document(name="name_value"), + ) + + +def test_create_document_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + document.ImportDocumentsRequest, + dict, + ], +) +def test_import_documents_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.import_documents(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_import_documents_rest_required_fields( + request_type=document.ImportDocumentsRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).import_documents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).import_documents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.import_documents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_import_documents_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.import_documents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "documentTemplate", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_import_documents_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.DocumentsRestInterceptor, "post_import_documents" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_import_documents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = document.ImportDocumentsRequest.pb( + document.ImportDocumentsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = document.ImportDocumentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.import_documents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_import_documents_rest_bad_request( + transport: str = "rest", request_type=document.ImportDocumentsRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.import_documents(request) + + +def test_import_documents_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + document.DeleteDocumentRequest, + dict, + ], +) +def test_delete_document_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_document(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_delete_document_rest_required_fields( + request_type=document.DeleteDocumentRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_document(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_document_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_document._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_document_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.DocumentsRestInterceptor, "post_delete_document" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_delete_document" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = document.DeleteDocumentRequest.pb(document.DeleteDocumentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = document.DeleteDocumentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.delete_document( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_delete_document_rest_bad_request( + transport: str = "rest", request_type=document.DeleteDocumentRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_document(request) + + +def test_delete_document_rest_flattened(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_document(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/knowledgeBases/*/documents/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_document_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_document( + document.DeleteDocumentRequest(), + name="name_value", + ) + + +def test_delete_document_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_document.UpdateDocumentRequest, + dict, + ], +) +def test_update_document_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "document": { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + } + request_init["document"] = { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3", + "display_name": "display_name_value", + "mime_type": "mime_type_value", + "knowledge_types": [1], + "content_uri": "content_uri_value", + "content": "content_value", + "raw_content": b"raw_content_blob", + "enable_auto_reload": True, + "latest_reload_status": { + "time": {"seconds": 751, "nanos": 543}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + "metadata": {}, + "state": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_document(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_update_document_rest_required_fields( + request_type=gcd_document.UpdateDocumentRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_document._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_document(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_document_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_document._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("document",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_document_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.DocumentsRestInterceptor, "post_update_document" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_update_document" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_document.UpdateDocumentRequest.pb( + gcd_document.UpdateDocumentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = gcd_document.UpdateDocumentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.update_document( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_document_rest_bad_request( + transport: str = "rest", request_type=gcd_document.UpdateDocumentRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "document": { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + } + request_init["document"] = { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3", + "display_name": "display_name_value", + "mime_type": "mime_type_value", + "knowledge_types": [1], + "content_uri": "content_uri_value", + "content": "content_value", + "raw_content": b"raw_content_blob", + "enable_auto_reload": True, + "latest_reload_status": { + "time": {"seconds": 751, "nanos": 543}, + "status": { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + }, + }, + "metadata": {}, + "state": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_document(request) + + +def test_update_document_rest_flattened(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "document": { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + } + + # get truthy value for each flattened field + mock_args = dict( + document=gcd_document.Document(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_document(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{document.name=projects/*/knowledgeBases/*/documents/*}" + % client.transport._host, + args[1], + ) + + +def test_update_document_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_document( + gcd_document.UpdateDocumentRequest(), + document=gcd_document.Document(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_document_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + document.ReloadDocumentRequest, + dict, + ], +) +def test_reload_document_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.reload_document(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_reload_document_rest_required_fields( + request_type=document.ReloadDocumentRequest, +): + transport_class = transports.DocumentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).reload_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).reload_document._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.reload_document(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_reload_document_rest_unset_required_fields(): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.reload_document._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_reload_document_rest_interceptors(null_interceptor): + transport = transports.DocumentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.DocumentsRestInterceptor(), + ) + client = DocumentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.DocumentsRestInterceptor, "post_reload_document" + ) as post, mock.patch.object( + transports.DocumentsRestInterceptor, "pre_reload_document" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = document.ReloadDocumentRequest.pb(document.ReloadDocumentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = document.ReloadDocumentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.reload_document( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_reload_document_rest_bad_request( + transport: str = "rest", request_type=document.ReloadDocumentRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2/documents/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.reload_document(request) + + +def test_reload_document_rest_flattened(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/knowledgeBases/sample2/documents/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.reload_document(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/knowledgeBases/*/documents/*}:reload" + % client.transport._host, + args[1], + ) + + +def test_reload_document_rest_flattened_error(transport: str = "rest"): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.reload_document( + document.ReloadDocumentRequest(), + name="name_value", + gcs_source=gcs.GcsSource(uri="uri_value"), + ) + + +def test_reload_document_rest_error(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = DocumentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = DocumentsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = DocumentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = DocumentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = DocumentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.DocumentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.DocumentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.DocumentsGrpcTransport, + transports.DocumentsGrpcAsyncIOTransport, + transports.DocumentsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = DocumentsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.DocumentsGrpcTransport, + ) + + +def test_documents_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.DocumentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_documents_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2beta1.services.documents.transports.DocumentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.DocumentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_documents", + "get_document", + "create_document", + "import_documents", + "delete_document", + "update_document", + "reload_document", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_documents_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.dialogflow_v2beta1.services.documents.transports.DocumentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.DocumentsTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_documents_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.dialogflow_v2beta1.services.documents.transports.DocumentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.DocumentsTransport() + adc.assert_called_once() + + +def test_documents_auth_adc(): # If no credentials are provided, we should use ADC credentials. with mock.patch.object(google.auth, "default", autospec=True) as adc: adc.return_value = (ga_credentials.AnonymousCredentials(), None) @@ -2666,6 +4685,7 @@ def test_documents_transport_auth_adc(transport_class): [ transports.DocumentsGrpcTransport, transports.DocumentsGrpcAsyncIOTransport, + transports.DocumentsRestTransport, ], ) def test_documents_transport_auth_gdch_credentials(transport_class): @@ -2763,11 +4783,40 @@ def test_documents_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_documents_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.DocumentsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_documents_rest_lro_client(): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_documents_host_no_port(transport_name): @@ -2778,7 +4827,11 @@ def test_documents_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2786,6 +4839,7 @@ def test_documents_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_documents_host_with_port(transport_name): @@ -2796,7 +4850,51 @@ def test_documents_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_documents_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = DocumentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = DocumentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_documents._session + session2 = client2.transport.list_documents._session + assert session1 != session2 + session1 = client1.transport.get_document._session + session2 = client2.transport.get_document._session + assert session1 != session2 + session1 = client1.transport.create_document._session + session2 = client2.transport.create_document._session + assert session1 != session2 + session1 = client1.transport.import_documents._session + session2 = client2.transport.import_documents._session + assert session1 != session2 + session1 = client1.transport.delete_document._session + session2 = client2.transport.delete_document._session + assert session1 != session2 + session1 = client1.transport.update_document._session + session2 = client2.transport.update_document._session + assert session1 != session2 + session1 = client1.transport.reload_document._session + session2 = client2.transport.reload_document._session + assert session1 != session2 def test_documents_grpc_transport_channel(): @@ -3117,6 +5215,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = DocumentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = DocumentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3834,6 +6218,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3851,6 +6236,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_entity_types.py b/tests/unit/gapic/dialogflow_v2beta1/test_entity_types.py index 8e1f53c71..6bb16b72b 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_entity_types.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_entity_types.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -44,12 +46,15 @@ from google.oauth2 import service_account from google.protobuf import empty_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.entity_types import ( EntityTypesAsyncClient, @@ -107,6 +112,7 @@ def test__get_default_mtls_endpoint(): [ (EntityTypesClient, "grpc"), (EntityTypesAsyncClient, "grpc_asyncio"), + (EntityTypesClient, "rest"), ], ) def test_entity_types_client_from_service_account_info(client_class, transport_name): @@ -120,7 +126,11 @@ def test_entity_types_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -128,6 +138,7 @@ def test_entity_types_client_from_service_account_info(client_class, transport_n [ (transports.EntityTypesGrpcTransport, "grpc"), (transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.EntityTypesRestTransport, "rest"), ], ) def test_entity_types_client_service_account_always_use_jwt( @@ -153,6 +164,7 @@ def test_entity_types_client_service_account_always_use_jwt( [ (EntityTypesClient, "grpc"), (EntityTypesAsyncClient, "grpc_asyncio"), + (EntityTypesClient, "rest"), ], ) def test_entity_types_client_from_service_account_file(client_class, transport_name): @@ -173,13 +185,18 @@ def test_entity_types_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_entity_types_client_get_transport_class(): transport = EntityTypesClient.get_transport_class() available_transports = [ transports.EntityTypesGrpcTransport, + transports.EntityTypesRestTransport, ] assert transport in available_transports @@ -196,6 +213,7 @@ def test_entity_types_client_get_transport_class(): transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest"), ], ) @mock.patch.object( @@ -339,6 +357,8 @@ def test_entity_types_client_client_options( "grpc_asyncio", "false", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", "true"), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -532,6 +552,7 @@ def test_entity_types_client_get_mtls_endpoint_and_cert_source(client_class): transports.EntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest"), ], ) def test_entity_types_client_client_options_scopes( @@ -567,6 +588,7 @@ def test_entity_types_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (EntityTypesClient, transports.EntityTypesRestTransport, "rest", None), ], ) def test_entity_types_client_client_options_credentials_file( @@ -3389,127 +3411,2958 @@ async def test_batch_delete_entities_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.EntityTypesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + entity_type.ListEntityTypesRequest, + dict, + ], +) +def test_list_entity_types_rest(request_type): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = EntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = entity_type.ListEntityTypesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.EntityTypesGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.ListEntityTypesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_entity_types(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListEntityTypesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_entity_types_rest_required_fields( + request_type=entity_type.ListEntityTypesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_entity_types._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = entity_type.ListEntityTypesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = entity_type.ListEntityTypesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_entity_types(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_entity_types_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + + unset_fields = transport.list_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.EntityTypesGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_entity_types_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options=options, - transport=transport, + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EntityTypesRestInterceptor, "post_list_entity_types" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_list_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.ListEntityTypesRequest.pb( + entity_type.ListEntityTypesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = entity_type.ListEntityTypesResponse.to_json( + entity_type.ListEntityTypesResponse() ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = entity_type.ListEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = entity_type.ListEntityTypesResponse() + + client.list_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.EntityTypesGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_entity_types_rest_bad_request( + transport: str = "rest", request_type=entity_type.ListEntityTypesRequest +): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = EntityTypesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.EntityTypesGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_entity_types(request) + + +def test_list_entity_types_rest_flattened(): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = EntityTypesClient(transport=transport) - assert client.transport is transport + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = entity_type.ListEntityTypesResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.EntityTypesGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.ListEntityTypesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_entity_types(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent}/entityTypes" % client.transport._host, + args[1], + ) + + +def test_list_entity_types_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.EntityTypesGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_entity_types( + entity_type.ListEntityTypesRequest(), + parent="parent_value", + language_code="language_code_value", + ) + + +def test_list_entity_types_rest_pager(transport: str = "rest"): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + entity_type.EntityType(), + entity_type.EntityType(), + ], + next_page_token="abc", + ), + entity_type.ListEntityTypesResponse( + entity_types=[], + next_page_token="def", + ), + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + ], + next_page_token="ghi", + ), + entity_type.ListEntityTypesResponse( + entity_types=[ + entity_type.EntityType(), + entity_type.EntityType(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + entity_type.ListEntityTypesResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values -@pytest.mark.parametrize( - "transport_class", - [ - transports.EntityTypesGrpcTransport, - transports.EntityTypesGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1/agent"} + + pager = client.list_entity_types(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, entity_type.EntityType) for i in results) + + pages = list(client.list_entity_types(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + entity_type.GetEntityTypeRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = EntityTypesClient.get_transport_class(transport_name)( +def test_get_entity_type_rest(request_type): + client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + + +def test_get_entity_type_rest_required_fields( + request_type=entity_type.GetEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = entity_type.EntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.EntityTypesGrpcTransport, + + unset_fields = transport.get_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(("languageCode",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EntityTypesRestInterceptor, "post_get_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_get_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.GetEntityTypeRequest.pb( + entity_type.GetEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = entity_type.EntityType.to_json( + entity_type.EntityType() + ) + request = entity_type.GetEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = entity_type.EntityType() -def test_entity_types_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.EntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + client.get_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_entity_type_rest_bad_request( + transport: str = "rest", request_type=entity_type.GetEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_entity_type(request) + + +def test_get_entity_type_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/entityTypes/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/agent/entityTypes/*}" % client.transport._host, + args[1], + ) + + +def test_get_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_entity_type( + entity_type.GetEntityTypeRequest(), + name="name_value", + language_code="language_code_value", + ) + + +def test_get_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_entity_type.CreateEntityTypeRequest, + dict, + ], +) +def test_create_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["entity_type"] = { + "name": "name_value", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "enable_fuzzy_extraction": True, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=gcd_entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=gcd_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == gcd_entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == gcd_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + + +def test_create_entity_type_rest_required_fields( + request_type=gcd_entity_type.CreateEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("language_code",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("languageCode",)) + & set( + ( + "parent", + "entityType", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EntityTypesRestInterceptor, "post_create_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_create_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_entity_type.CreateEntityTypeRequest.pb( + gcd_entity_type.CreateEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_entity_type.EntityType.to_json( + gcd_entity_type.EntityType() + ) + + request = gcd_entity_type.CreateEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_entity_type.EntityType() + + client.create_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_entity_type_rest_bad_request( + transport: str = "rest", request_type=gcd_entity_type.CreateEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["entity_type"] = { + "name": "name_value", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "enable_fuzzy_extraction": True, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_entity_type(request) + + +def test_create_entity_type_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entity_type=gcd_entity_type.EntityType(name="name_value"), + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent}/entityTypes" % client.transport._host, + args[1], + ) + + +def test_create_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_entity_type( + gcd_entity_type.CreateEntityTypeRequest(), + parent="parent_value", + entity_type=gcd_entity_type.EntityType(name="name_value"), + language_code="language_code_value", + ) + + +def test_create_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_entity_type.UpdateEntityTypeRequest, + dict, + ], +) +def test_update_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "entity_type": {"name": "projects/sample1/agent/entityTypes/sample2"} + } + request_init["entity_type"] = { + "name": "projects/sample1/agent/entityTypes/sample2", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "enable_fuzzy_extraction": True, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType( + name="name_value", + display_name="display_name_value", + kind=gcd_entity_type.EntityType.Kind.KIND_MAP, + auto_expansion_mode=gcd_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, + enable_fuzzy_extraction=True, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_entity_type.EntityType) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.kind == gcd_entity_type.EntityType.Kind.KIND_MAP + assert ( + response.auto_expansion_mode + == gcd_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT + ) + assert response.enable_fuzzy_extraction is True + + +def test_update_entity_type_rest_required_fields( + request_type=gcd_entity_type.UpdateEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "languageCode", + "updateMask", + ) + ) + & set(("entityType",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EntityTypesRestInterceptor, "post_update_entity_type" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_update_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_entity_type.UpdateEntityTypeRequest.pb( + gcd_entity_type.UpdateEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_entity_type.EntityType.to_json( + gcd_entity_type.EntityType() + ) + + request = gcd_entity_type.UpdateEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_entity_type.EntityType() + + client.update_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_entity_type_rest_bad_request( + transport: str = "rest", request_type=gcd_entity_type.UpdateEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "entity_type": {"name": "projects/sample1/agent/entityTypes/sample2"} + } + request_init["entity_type"] = { + "name": "projects/sample1/agent/entityTypes/sample2", + "display_name": "display_name_value", + "kind": 1, + "auto_expansion_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + "enable_fuzzy_extraction": True, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_entity_type(request) + + +def test_update_entity_type_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_entity_type.EntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "entity_type": {"name": "projects/sample1/agent/entityTypes/sample2"} + } + + # get truthy value for each flattened field + mock_args = dict( + entity_type=gcd_entity_type.EntityType(name="name_value"), + language_code="language_code_value", + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_entity_type.EntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{entity_type.name=projects/*/agent/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_update_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_entity_type( + gcd_entity_type.UpdateEntityTypeRequest(), + entity_type=gcd_entity_type.EntityType(name="name_value"), + language_code="language_code_value", + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.DeleteEntityTypeRequest, + dict, + ], +) +def test_delete_entity_type_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_entity_type(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_entity_type_rest_required_fields( + request_type=entity_type.DeleteEntityTypeRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_entity_type_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_entity_type_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_delete_entity_type" + ) as pre: + pre.assert_not_called() + pb_message = entity_type.DeleteEntityTypeRequest.pb( + entity_type.DeleteEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = entity_type.DeleteEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_entity_type_rest_bad_request( + transport: str = "rest", request_type=entity_type.DeleteEntityTypeRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_entity_type(request) + + +def test_delete_entity_type_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/entityTypes/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/agent/entityTypes/*}" % client.transport._host, + args[1], + ) + + +def test_delete_entity_type_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_entity_type( + entity_type.DeleteEntityTypeRequest(), + name="name_value", + ) + + +def test_delete_entity_type_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.BatchUpdateEntityTypesRequest, + dict, + ], +) +def test_batch_update_entity_types_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_update_entity_types(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_update_entity_types_rest_required_fields( + request_type=entity_type.BatchUpdateEntityTypesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_update_entity_types(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_update_entity_types_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_update_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_update_entity_types_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.EntityTypesRestInterceptor, "post_batch_update_entity_types" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_batch_update_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.BatchUpdateEntityTypesRequest.pb( + entity_type.BatchUpdateEntityTypesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = entity_type.BatchUpdateEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_update_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_update_entity_types_rest_bad_request( + transport: str = "rest", request_type=entity_type.BatchUpdateEntityTypesRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_update_entity_types(request) + + +def test_batch_update_entity_types_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.BatchDeleteEntityTypesRequest, + dict, + ], +) +def test_batch_delete_entity_types_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_delete_entity_types(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_delete_entity_types_rest_required_fields( + request_type=entity_type.BatchDeleteEntityTypesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["entity_type_names"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + jsonified_request["entityTypeNames"] = "entity_type_names_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + assert "entityTypeNames" in jsonified_request + assert jsonified_request["entityTypeNames"] == "entity_type_names_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_delete_entity_types(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_delete_entity_types_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_delete_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "entityTypeNames", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_delete_entity_types_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.EntityTypesRestInterceptor, "post_batch_delete_entity_types" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_batch_delete_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.BatchDeleteEntityTypesRequest.pb( + entity_type.BatchDeleteEntityTypesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = entity_type.BatchDeleteEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_delete_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_delete_entity_types_rest_bad_request( + transport: str = "rest", request_type=entity_type.BatchDeleteEntityTypesRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_delete_entity_types(request) + + +def test_batch_delete_entity_types_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entity_type_names=["entity_type_names_value"], + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_delete_entity_types(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent}/entityTypes:batchDelete" + % client.transport._host, + args[1], + ) + + +def test_batch_delete_entity_types_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_delete_entity_types( + entity_type.BatchDeleteEntityTypesRequest(), + parent="parent_value", + entity_type_names=["entity_type_names_value"], + ) + + +def test_batch_delete_entity_types_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.BatchCreateEntitiesRequest, + dict, + ], +) +def test_batch_create_entities_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_create_entities(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_create_entities_rest_required_fields( + request_type=entity_type.BatchCreateEntitiesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_create_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_create_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_create_entities(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_create_entities_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_create_entities._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "entities", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_create_entities_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.EntityTypesRestInterceptor, "post_batch_create_entities" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_batch_create_entities" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.BatchCreateEntitiesRequest.pb( + entity_type.BatchCreateEntitiesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = entity_type.BatchCreateEntitiesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_create_entities( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_create_entities_rest_bad_request( + transport: str = "rest", request_type=entity_type.BatchCreateEntitiesRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_create_entities(request) + + +def test_batch_create_entities_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/entityTypes/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entities=[entity_type.EntityType.Entity(value="value_value")], + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_create_entities(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent/entityTypes/*}/entities:batchCreate" + % client.transport._host, + args[1], + ) + + +def test_batch_create_entities_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_create_entities( + entity_type.BatchCreateEntitiesRequest(), + parent="parent_value", + entities=[entity_type.EntityType.Entity(value="value_value")], + language_code="language_code_value", + ) + + +def test_batch_create_entities_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.BatchUpdateEntitiesRequest, + dict, + ], +) +def test_batch_update_entities_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_update_entities(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_update_entities_rest_required_fields( + request_type=entity_type.BatchUpdateEntitiesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_update_entities(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_update_entities_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_update_entities._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "entities", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_update_entities_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.EntityTypesRestInterceptor, "post_batch_update_entities" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_batch_update_entities" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.BatchUpdateEntitiesRequest.pb( + entity_type.BatchUpdateEntitiesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = entity_type.BatchUpdateEntitiesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_update_entities( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_update_entities_rest_bad_request( + transport: str = "rest", request_type=entity_type.BatchUpdateEntitiesRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_update_entities(request) + + +def test_batch_update_entities_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/entityTypes/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entities=[entity_type.EntityType.Entity(value="value_value")], + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_update_entities(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent/entityTypes/*}/entities:batchUpdate" + % client.transport._host, + args[1], + ) + + +def test_batch_update_entities_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_update_entities( + entity_type.BatchUpdateEntitiesRequest(), + parent="parent_value", + entities=[entity_type.EntityType.Entity(value="value_value")], + language_code="language_code_value", + ) + + +def test_batch_update_entities_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + entity_type.BatchDeleteEntitiesRequest, + dict, + ], +) +def test_batch_delete_entities_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_delete_entities(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_delete_entities_rest_required_fields( + request_type=entity_type.BatchDeleteEntitiesRequest, +): + transport_class = transports.EntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["entity_values"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + jsonified_request["entityValues"] = "entity_values_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_entities._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + assert "entityValues" in jsonified_request + assert jsonified_request["entityValues"] == "entity_values_value" + + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_delete_entities(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_delete_entities_rest_unset_required_fields(): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_delete_entities._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "entityValues", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_delete_entities_rest_interceptors(null_interceptor): + transport = transports.EntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EntityTypesRestInterceptor(), + ) + client = EntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.EntityTypesRestInterceptor, "post_batch_delete_entities" + ) as post, mock.patch.object( + transports.EntityTypesRestInterceptor, "pre_batch_delete_entities" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = entity_type.BatchDeleteEntitiesRequest.pb( + entity_type.BatchDeleteEntitiesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = entity_type.BatchDeleteEntitiesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_delete_entities( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_delete_entities_rest_bad_request( + transport: str = "rest", request_type=entity_type.BatchDeleteEntitiesRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/entityTypes/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_delete_entities(request) + + +def test_batch_delete_entities_rest_flattened(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/entityTypes/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + entity_values=["entity_values_value"], + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_delete_entities(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent/entityTypes/*}/entities:batchDelete" + % client.transport._host, + args[1], + ) + + +def test_batch_delete_entities_rest_flattened_error(transport: str = "rest"): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_delete_entities( + entity_type.BatchDeleteEntitiesRequest(), + parent="parent_value", + entity_values=["entity_values_value"], + language_code="language_code_value", + ) + + +def test_batch_delete_entities_rest_error(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EntityTypesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = EntityTypesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.EntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.EntityTypesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.EntityTypesGrpcTransport, + transports.EntityTypesGrpcAsyncIOTransport, + transports.EntityTypesRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = EntityTypesClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.EntityTypesGrpcTransport, + ) + + +def test_entity_types_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.EntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", ) @@ -3641,6 +6494,7 @@ def test_entity_types_transport_auth_adc(transport_class): [ transports.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport, + transports.EntityTypesRestTransport, ], ) def test_entity_types_transport_auth_gdch_credentials(transport_class): @@ -3738,11 +6592,40 @@ def test_entity_types_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_entity_types_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.EntityTypesRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_entity_types_rest_lro_client(): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_entity_types_host_no_port(transport_name): @@ -3753,7 +6636,11 @@ def test_entity_types_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3761,6 +6648,7 @@ def test_entity_types_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_entity_types_host_with_port(transport_name): @@ -3771,7 +6659,60 @@ def test_entity_types_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_entity_types_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = EntityTypesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = EntityTypesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_entity_types._session + session2 = client2.transport.list_entity_types._session + assert session1 != session2 + session1 = client1.transport.get_entity_type._session + session2 = client2.transport.get_entity_type._session + assert session1 != session2 + session1 = client1.transport.create_entity_type._session + session2 = client2.transport.create_entity_type._session + assert session1 != session2 + session1 = client1.transport.update_entity_type._session + session2 = client2.transport.update_entity_type._session + assert session1 != session2 + session1 = client1.transport.delete_entity_type._session + session2 = client2.transport.delete_entity_type._session + assert session1 != session2 + session1 = client1.transport.batch_update_entity_types._session + session2 = client2.transport.batch_update_entity_types._session + assert session1 != session2 + session1 = client1.transport.batch_delete_entity_types._session + session2 = client2.transport.batch_delete_entity_types._session + assert session1 != session2 + session1 = client1.transport.batch_create_entities._session + session2 = client2.transport.batch_create_entities._session + assert session1 != session2 + session1 = client1.transport.batch_update_entities._session + session2 = client2.transport.batch_update_entities._session + assert session1 != session2 + session1 = client1.transport.batch_delete_entities._session + session2 = client2.transport.batch_delete_entities._session + assert session1 != session2 def test_entity_types_grpc_transport_channel(): @@ -4089,6 +7030,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = EntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = EntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4806,6 +8033,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4823,6 +8051,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_environments.py b/tests/unit/gapic/dialogflow_v2beta1/test_environments.py index 71db45c90..67486df60 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_environments.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_environments.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,12 +36,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.environments import ( EnvironmentsAsyncClient, @@ -96,6 +101,7 @@ def test__get_default_mtls_endpoint(): [ (EnvironmentsClient, "grpc"), (EnvironmentsAsyncClient, "grpc_asyncio"), + (EnvironmentsClient, "rest"), ], ) def test_environments_client_from_service_account_info(client_class, transport_name): @@ -109,7 +115,11 @@ def test_environments_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -117,6 +127,7 @@ def test_environments_client_from_service_account_info(client_class, transport_n [ (transports.EnvironmentsGrpcTransport, "grpc"), (transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.EnvironmentsRestTransport, "rest"), ], ) def test_environments_client_service_account_always_use_jwt( @@ -142,6 +153,7 @@ def test_environments_client_service_account_always_use_jwt( [ (EnvironmentsClient, "grpc"), (EnvironmentsAsyncClient, "grpc_asyncio"), + (EnvironmentsClient, "rest"), ], ) def test_environments_client_from_service_account_file(client_class, transport_name): @@ -162,13 +174,18 @@ def test_environments_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_environments_client_get_transport_class(): transport = EnvironmentsClient.get_transport_class() available_transports = [ transports.EnvironmentsGrpcTransport, + transports.EnvironmentsRestTransport, ] assert transport in available_transports @@ -185,6 +202,7 @@ def test_environments_client_get_transport_class(): transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -328,6 +346,8 @@ def test_environments_client_client_options( "grpc_asyncio", "false", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", "true"), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -521,6 +541,7 @@ def test_environments_client_get_mtls_endpoint_and_cert_source(client_class): transports.EnvironmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest"), ], ) def test_environments_client_client_options_scopes( @@ -561,6 +582,7 @@ def test_environments_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (EnvironmentsClient, transports.EnvironmentsRestTransport, "rest", None), ], ) def test_environments_client_client_options_credentials_file( @@ -2135,138 +2157,1765 @@ async def test_get_environment_history_async_pages(): assert page_.raw_page.next_page_token == token -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.EnvironmentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + environment.ListEnvironmentsRequest, + dict, + ], +) +def test_list_environments_rest(request_type): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.ListEnvironmentsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.ListEnvironmentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_environments(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListEnvironmentsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_environments_rest_required_fields( + request_type=environment.ListEnvironmentsRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_environments._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_environments._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.ListEnvironmentsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = environment.ListEnvironmentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_environments(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_environments_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_environments._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_environments_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options=options, - transport=transport, + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "post_list_environments" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_list_environments" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.ListEnvironmentsRequest.pb( + environment.ListEnvironmentsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = environment.ListEnvironmentsResponse.to_json( + environment.ListEnvironmentsResponse() ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = environment.ListEnvironmentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.ListEnvironmentsResponse() + + client.list_environments( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.EnvironmentsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_environments_rest_bad_request( + transport: str = "rest", request_type=environment.ListEnvironmentsRequest +): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = EnvironmentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.EnvironmentsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_environments(request) + + +def test_list_environments_rest_flattened(): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = EnvironmentsClient(transport=transport) - assert client.transport is transport + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.ListEnvironmentsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.EnvironmentsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.ListEnvironmentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_environments(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent}/environments" + % client.transport._host, + args[1], + ) + + +def test_list_environments_rest_flattened_error(transport: str = "rest"): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.EnvironmentsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_environments( + environment.ListEnvironmentsRequest(), + parent="parent_value", + ) + + +def test_list_environments_rest_pager(transport: str = "rest"): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + environment.Environment(), + environment.Environment(), + ], + next_page_token="abc", + ), + environment.ListEnvironmentsResponse( + environments=[], + next_page_token="def", + ), + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + ], + next_page_token="ghi", + ), + environment.ListEnvironmentsResponse( + environments=[ + environment.Environment(), + environment.Environment(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + environment.ListEnvironmentsResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values -@pytest.mark.parametrize( - "transport_class", - [ - transports.EnvironmentsGrpcTransport, - transports.EnvironmentsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1/agent"} + + pager = client.list_environments(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, environment.Environment) for i in results) + + pages = list(client.list_environments(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + environment.GetEnvironmentRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = EnvironmentsClient.get_transport_class(transport_name)( +def test_get_environment_rest(request_type): + client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.Environment( + name="name_value", + description="description_value", + agent_version="agent_version_value", + state=environment.Environment.State.STOPPED, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_environment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, environment.Environment) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.agent_version == "agent_version_value" + assert response.state == environment.Environment.State.STOPPED + + +def test_get_environment_rest_required_fields( + request_type=environment.GetEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - assert isinstance( - client.transport, - transports.EnvironmentsGrpcTransport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.Environment() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) + unset_fields = transport.get_environment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) -def test_environments_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.EnvironmentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", - ) +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "post_get_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_get_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.GetEnvironmentRequest.pb( + environment.GetEnvironmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = environment.Environment.to_json( + environment.Environment() + ) -def test_environments_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2beta1.services.environments.transports.EnvironmentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.EnvironmentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + request = environment.GetEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.Environment() + + client.get_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_environment_rest_bad_request( + transport: str = "rest", request_type=environment.GetEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_environment(request) + + +def test_get_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.CreateEnvironmentRequest, + dict, + ], +) +def test_create_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["environment"] = { + "name": "name_value", + "description": "description_value", + "agent_version": "agent_version_value", + "state": 1, + "update_time": {"seconds": 751, "nanos": 543}, + "text_to_speech_settings": { + "enable_text_to_speech": True, + "output_audio_encoding": 1, + "sample_rate_hertz": 1817, + "synthesize_speech_configs": {}, + }, + "fulfillment": { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.Environment( + name="name_value", + description="description_value", + agent_version="agent_version_value", + state=environment.Environment.State.STOPPED, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_environment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, environment.Environment) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.agent_version == "agent_version_value" + assert response.state == environment.Environment.State.STOPPED + + +def test_create_environment_rest_required_fields( + request_type=environment.CreateEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["parent"] = "" + request_init["environment_id"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + assert "environmentId" not in jsonified_request + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + assert "environmentId" in jsonified_request + assert jsonified_request["environmentId"] == request_init["environment_id"] + + jsonified_request["parent"] = "parent_value" + jsonified_request["environmentId"] = "environment_id_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_environment._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("environment_id",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + assert "environmentId" in jsonified_request + assert jsonified_request["environmentId"] == "environment_id_value" + + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.Environment() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_environment(request) + + expected_params = [ + ( + "environmentId", + "", + ), + ("$alt", "json;enum-encoding=int"), + ] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_environment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("environmentId",)) + & set( + ( + "parent", + "environment", + "environmentId", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "post_create_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_create_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.CreateEnvironmentRequest.pb( + environment.CreateEnvironmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = environment.Environment.to_json( + environment.Environment() + ) + + request = environment.CreateEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.Environment() + + client.create_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_environment_rest_bad_request( + transport: str = "rest", request_type=environment.CreateEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["environment"] = { + "name": "name_value", + "description": "description_value", + "agent_version": "agent_version_value", + "state": 1, + "update_time": {"seconds": 751, "nanos": 543}, + "text_to_speech_settings": { + "enable_text_to_speech": True, + "output_audio_encoding": 1, + "sample_rate_hertz": 1817, + "synthesize_speech_configs": {}, + }, + "fulfillment": { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_environment(request) + + +def test_create_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.UpdateEnvironmentRequest, + dict, + ], +) +def test_update_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": {"name": "projects/sample1/agent/environments/sample2"} + } + request_init["environment"] = { + "name": "projects/sample1/agent/environments/sample2", + "description": "description_value", + "agent_version": "agent_version_value", + "state": 1, + "update_time": {"seconds": 751, "nanos": 543}, + "text_to_speech_settings": { + "enable_text_to_speech": True, + "output_audio_encoding": 1, + "sample_rate_hertz": 1817, + "synthesize_speech_configs": {}, + }, + "fulfillment": { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.Environment( + name="name_value", + description="description_value", + agent_version="agent_version_value", + state=environment.Environment.State.STOPPED, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_environment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, environment.Environment) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.agent_version == "agent_version_value" + assert response.state == environment.Environment.State.STOPPED + + +def test_update_environment_rest_required_fields( + request_type=environment.UpdateEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_environment._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "allow_load_to_draft_and_discard_changes", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.Environment() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = environment.Environment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_environment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "allowLoadToDraftAndDiscardChanges", + "updateMask", + ) + ) + & set( + ( + "environment", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "post_update_environment" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_update_environment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.UpdateEnvironmentRequest.pb( + environment.UpdateEnvironmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = environment.Environment.to_json( + environment.Environment() + ) + + request = environment.UpdateEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.Environment() + + client.update_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_environment_rest_bad_request( + transport: str = "rest", request_type=environment.UpdateEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "environment": {"name": "projects/sample1/agent/environments/sample2"} + } + request_init["environment"] = { + "name": "projects/sample1/agent/environments/sample2", + "description": "description_value", + "agent_version": "agent_version_value", + "state": 1, + "update_time": {"seconds": 751, "nanos": 543}, + "text_to_speech_settings": { + "enable_text_to_speech": True, + "output_audio_encoding": 1, + "sample_rate_hertz": 1817, + "synthesize_speech_configs": {}, + }, + "fulfillment": { + "name": "name_value", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + }, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_environment(request) + + +def test_update_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.DeleteEnvironmentRequest, + dict, + ], +) +def test_delete_environment_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_environment(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_environment_rest_required_fields( + request_type=environment.DeleteEnvironmentRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_environment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_environment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_environment_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_environment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_environment_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_delete_environment" + ) as pre: + pre.assert_not_called() + pb_message = environment.DeleteEnvironmentRequest.pb( + environment.DeleteEnvironmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = environment.DeleteEnvironmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_environment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_environment_rest_bad_request( + transport: str = "rest", request_type=environment.DeleteEnvironmentRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_environment(request) + + +def test_delete_environment_rest_error(): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + environment.GetEnvironmentHistoryRequest, + dict, + ], +) +def test_get_environment_history_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = environment.EnvironmentHistory( + parent="parent_value", + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = environment.EnvironmentHistory.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_environment_history(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.GetEnvironmentHistoryPager) + assert response.parent == "parent_value" + assert response.next_page_token == "next_page_token_value" + + +def test_get_environment_history_rest_required_fields( + request_type=environment.GetEnvironmentHistoryRequest, +): + transport_class = transports.EnvironmentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_environment_history._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_environment_history._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = environment.EnvironmentHistory() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = environment.EnvironmentHistory.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_environment_history(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_environment_history_rest_unset_required_fields(): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_environment_history._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_environment_history_rest_interceptors(null_interceptor): + transport = transports.EnvironmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.EnvironmentsRestInterceptor(), + ) + client = EnvironmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.EnvironmentsRestInterceptor, "post_get_environment_history" + ) as post, mock.patch.object( + transports.EnvironmentsRestInterceptor, "pre_get_environment_history" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = environment.GetEnvironmentHistoryRequest.pb( + environment.GetEnvironmentHistoryRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = environment.EnvironmentHistory.to_json( + environment.EnvironmentHistory() + ) + + request = environment.GetEnvironmentHistoryRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = environment.EnvironmentHistory() + + client.get_environment_history( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_environment_history_rest_bad_request( + transport: str = "rest", request_type=environment.GetEnvironmentHistoryRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/environments/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_environment_history(request) + + +def test_get_environment_history_rest_pager(transport: str = "rest"): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + environment.EnvironmentHistory( + entries=[ + environment.EnvironmentHistory.Entry(), + environment.EnvironmentHistory.Entry(), + environment.EnvironmentHistory.Entry(), + ], + next_page_token="abc", + ), + environment.EnvironmentHistory( + entries=[], + next_page_token="def", + ), + environment.EnvironmentHistory( + entries=[ + environment.EnvironmentHistory.Entry(), + ], + next_page_token="ghi", + ), + environment.EnvironmentHistory( + entries=[ + environment.EnvironmentHistory.Entry(), + environment.EnvironmentHistory.Entry(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(environment.EnvironmentHistory.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/agent/environments/sample2"} + + pager = client.get_environment_history(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, environment.EnvironmentHistory.Entry) for i in results) + + pages = list(client.get_environment_history(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = EnvironmentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = EnvironmentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.EnvironmentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.EnvironmentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.EnvironmentsGrpcTransport, + transports.EnvironmentsGrpcAsyncIOTransport, + transports.EnvironmentsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = EnvironmentsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.EnvironmentsGrpcTransport, + ) + + +def test_environments_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.EnvironmentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_environments_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2beta1.services.environments.transports.EnvironmentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.EnvironmentsTransport( + credentials=ga_credentials.AnonymousCredentials(), ) # Every method on the transport should just blindly @@ -2378,6 +4027,7 @@ def test_environments_transport_auth_adc(transport_class): [ transports.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport, + transports.EnvironmentsRestTransport, ], ) def test_environments_transport_auth_gdch_credentials(transport_class): @@ -2475,11 +4125,23 @@ def test_environments_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_environments_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.EnvironmentsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_environments_host_no_port(transport_name): @@ -2490,7 +4152,11 @@ def test_environments_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2498,6 +4164,7 @@ def test_environments_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_environments_host_with_port(transport_name): @@ -2508,7 +4175,48 @@ def test_environments_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_environments_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = EnvironmentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = EnvironmentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_environments._session + session2 = client2.transport.list_environments._session + assert session1 != session2 + session1 = client1.transport.get_environment._session + session2 = client2.transport.get_environment._session + assert session1 != session2 + session1 = client1.transport.create_environment._session + session2 = client2.transport.create_environment._session + assert session1 != session2 + session1 = client1.transport.update_environment._session + session2 = client2.transport.update_environment._session + assert session1 != session2 + session1 = client1.transport.delete_environment._session + session2 = client2.transport.delete_environment._session + assert session1 != session2 + session1 = client1.transport.get_environment_history._session + session2 = client2.transport.get_environment_history._session + assert session1 != session2 def test_environments_grpc_transport_channel(): @@ -2835,6 +4543,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = EnvironmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = EnvironmentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3552,6 +5546,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3569,6 +5564,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_fulfillments.py b/tests/unit/gapic/dialogflow_v2beta1/test_fulfillments.py index 1cc7a10c6..c15f165c9 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_fulfillments.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_fulfillments.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,11 +36,14 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.fulfillments import ( FulfillmentsAsyncClient, @@ -95,6 +100,7 @@ def test__get_default_mtls_endpoint(): [ (FulfillmentsClient, "grpc"), (FulfillmentsAsyncClient, "grpc_asyncio"), + (FulfillmentsClient, "rest"), ], ) def test_fulfillments_client_from_service_account_info(client_class, transport_name): @@ -108,7 +114,11 @@ def test_fulfillments_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -116,6 +126,7 @@ def test_fulfillments_client_from_service_account_info(client_class, transport_n [ (transports.FulfillmentsGrpcTransport, "grpc"), (transports.FulfillmentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.FulfillmentsRestTransport, "rest"), ], ) def test_fulfillments_client_service_account_always_use_jwt( @@ -141,6 +152,7 @@ def test_fulfillments_client_service_account_always_use_jwt( [ (FulfillmentsClient, "grpc"), (FulfillmentsAsyncClient, "grpc_asyncio"), + (FulfillmentsClient, "rest"), ], ) def test_fulfillments_client_from_service_account_file(client_class, transport_name): @@ -161,13 +173,18 @@ def test_fulfillments_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_fulfillments_client_get_transport_class(): transport = FulfillmentsClient.get_transport_class() available_transports = [ transports.FulfillmentsGrpcTransport, + transports.FulfillmentsRestTransport, ] assert transport in available_transports @@ -184,6 +201,7 @@ def test_fulfillments_client_get_transport_class(): transports.FulfillmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (FulfillmentsClient, transports.FulfillmentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -327,6 +345,8 @@ def test_fulfillments_client_client_options( "grpc_asyncio", "false", ), + (FulfillmentsClient, transports.FulfillmentsRestTransport, "rest", "true"), + (FulfillmentsClient, transports.FulfillmentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -520,6 +540,7 @@ def test_fulfillments_client_get_mtls_endpoint_and_cert_source(client_class): transports.FulfillmentsGrpcAsyncIOTransport, "grpc_asyncio", ), + (FulfillmentsClient, transports.FulfillmentsRestTransport, "rest"), ], ) def test_fulfillments_client_client_options_scopes( @@ -560,6 +581,7 @@ def test_fulfillments_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (FulfillmentsClient, transports.FulfillmentsRestTransport, "rest", None), ], ) def test_fulfillments_client_client_options_credentials_file( @@ -1184,6 +1206,589 @@ async def test_update_fulfillment_flattened_error_async(): ) +@pytest.mark.parametrize( + "request_type", + [ + fulfillment.GetFulfillmentRequest, + dict, + ], +) +def test_get_fulfillment_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/fulfillment"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = fulfillment.Fulfillment( + name="name_value", + display_name="display_name_value", + enabled=True, + generic_web_service=fulfillment.Fulfillment.GenericWebService( + uri="uri_value" + ), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_fulfillment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, fulfillment.Fulfillment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.enabled is True + + +def test_get_fulfillment_rest_required_fields( + request_type=fulfillment.GetFulfillmentRequest, +): + transport_class = transports.FulfillmentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_fulfillment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_fulfillment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = fulfillment.Fulfillment() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_fulfillment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_fulfillment_rest_unset_required_fields(): + transport = transports.FulfillmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_fulfillment._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_fulfillment_rest_interceptors(null_interceptor): + transport = transports.FulfillmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.FulfillmentsRestInterceptor(), + ) + client = FulfillmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.FulfillmentsRestInterceptor, "post_get_fulfillment" + ) as post, mock.patch.object( + transports.FulfillmentsRestInterceptor, "pre_get_fulfillment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = fulfillment.GetFulfillmentRequest.pb( + fulfillment.GetFulfillmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = fulfillment.Fulfillment.to_json( + fulfillment.Fulfillment() + ) + + request = fulfillment.GetFulfillmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = fulfillment.Fulfillment() + + client.get_fulfillment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_fulfillment_rest_bad_request( + transport: str = "rest", request_type=fulfillment.GetFulfillmentRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/fulfillment"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_fulfillment(request) + + +def test_get_fulfillment_rest_flattened(): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = fulfillment.Fulfillment() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/fulfillment"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_fulfillment(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/agent/fulfillment}" % client.transport._host, + args[1], + ) + + +def test_get_fulfillment_rest_flattened_error(transport: str = "rest"): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_fulfillment( + fulfillment.GetFulfillmentRequest(), + name="name_value", + ) + + +def test_get_fulfillment_rest_error(): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_fulfillment.UpdateFulfillmentRequest, + dict, + ], +) +def test_update_fulfillment_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"fulfillment": {"name": "projects/sample1/agent/fulfillment"}} + request_init["fulfillment"] = { + "name": "projects/sample1/agent/fulfillment", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_fulfillment.Fulfillment( + name="name_value", + display_name="display_name_value", + enabled=True, + generic_web_service=gcd_fulfillment.Fulfillment.GenericWebService( + uri="uri_value" + ), + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_fulfillment(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_fulfillment.Fulfillment) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.enabled is True + + +def test_update_fulfillment_rest_required_fields( + request_type=gcd_fulfillment.UpdateFulfillmentRequest, +): + transport_class = transports.FulfillmentsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_fulfillment._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_fulfillment._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_fulfillment.Fulfillment() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_fulfillment(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_fulfillment_rest_unset_required_fields(): + transport = transports.FulfillmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_fulfillment._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "fulfillment", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_fulfillment_rest_interceptors(null_interceptor): + transport = transports.FulfillmentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.FulfillmentsRestInterceptor(), + ) + client = FulfillmentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.FulfillmentsRestInterceptor, "post_update_fulfillment" + ) as post, mock.patch.object( + transports.FulfillmentsRestInterceptor, "pre_update_fulfillment" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_fulfillment.UpdateFulfillmentRequest.pb( + gcd_fulfillment.UpdateFulfillmentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_fulfillment.Fulfillment.to_json( + gcd_fulfillment.Fulfillment() + ) + + request = gcd_fulfillment.UpdateFulfillmentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_fulfillment.Fulfillment() + + client.update_fulfillment( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_fulfillment_rest_bad_request( + transport: str = "rest", request_type=gcd_fulfillment.UpdateFulfillmentRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"fulfillment": {"name": "projects/sample1/agent/fulfillment"}} + request_init["fulfillment"] = { + "name": "projects/sample1/agent/fulfillment", + "display_name": "display_name_value", + "generic_web_service": { + "uri": "uri_value", + "username": "username_value", + "password": "password_value", + "request_headers": {}, + "is_cloud_function": True, + }, + "enabled": True, + "features": [{"type_": 1}], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_fulfillment(request) + + +def test_update_fulfillment_rest_flattened(): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_fulfillment.Fulfillment() + + # get arguments that satisfy an http rule for this method + sample_request = {"fulfillment": {"name": "projects/sample1/agent/fulfillment"}} + + # get truthy value for each flattened field + mock_args = dict( + fulfillment=gcd_fulfillment.Fulfillment(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_fulfillment.Fulfillment.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_fulfillment(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{fulfillment.name=projects/*/agent/fulfillment}" + % client.transport._host, + args[1], + ) + + +def test_update_fulfillment_rest_flattened_error(transport: str = "rest"): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_fulfillment( + gcd_fulfillment.UpdateFulfillmentRequest(), + fulfillment=gcd_fulfillment.Fulfillment(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_fulfillment_rest_error(): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.FulfillmentsGrpcTransport( @@ -1265,6 +1870,7 @@ def test_transport_get_channel(): [ transports.FulfillmentsGrpcTransport, transports.FulfillmentsGrpcAsyncIOTransport, + transports.FulfillmentsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1279,6 +1885,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1423,6 +2030,7 @@ def test_fulfillments_transport_auth_adc(transport_class): [ transports.FulfillmentsGrpcTransport, transports.FulfillmentsGrpcAsyncIOTransport, + transports.FulfillmentsRestTransport, ], ) def test_fulfillments_transport_auth_gdch_credentials(transport_class): @@ -1520,11 +2128,23 @@ def test_fulfillments_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_fulfillments_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.FulfillmentsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_fulfillments_host_no_port(transport_name): @@ -1535,7 +2155,11 @@ def test_fulfillments_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1543,6 +2167,7 @@ def test_fulfillments_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_fulfillments_host_with_port(transport_name): @@ -1553,7 +2178,36 @@ def test_fulfillments_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_fulfillments_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = FulfillmentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = FulfillmentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.get_fulfillment._session + session2 = client2.transport.get_fulfillment._session + assert session1 != session2 + session1 = client1.transport.update_fulfillment._session + session2 = client2.transport.update_fulfillment._session + assert session1 != session2 def test_fulfillments_grpc_transport_channel(): @@ -1834,6 +2488,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = FulfillmentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = FulfillmentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2551,6 +3491,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2568,6 +3509,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_intents.py b/tests/unit/gapic/dialogflow_v2beta1/test_intents.py index cb7df263c..dd385d889 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_intents.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_intents.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import ( @@ -44,12 +46,15 @@ from google.oauth2 import service_account from google.protobuf import empty_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.intents import ( IntentsAsyncClient, @@ -105,6 +110,7 @@ def test__get_default_mtls_endpoint(): [ (IntentsClient, "grpc"), (IntentsAsyncClient, "grpc_asyncio"), + (IntentsClient, "rest"), ], ) def test_intents_client_from_service_account_info(client_class, transport_name): @@ -118,7 +124,11 @@ def test_intents_client_from_service_account_info(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -126,6 +136,7 @@ def test_intents_client_from_service_account_info(client_class, transport_name): [ (transports.IntentsGrpcTransport, "grpc"), (transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.IntentsRestTransport, "rest"), ], ) def test_intents_client_service_account_always_use_jwt(transport_class, transport_name): @@ -149,6 +160,7 @@ def test_intents_client_service_account_always_use_jwt(transport_class, transpor [ (IntentsClient, "grpc"), (IntentsAsyncClient, "grpc_asyncio"), + (IntentsClient, "rest"), ], ) def test_intents_client_from_service_account_file(client_class, transport_name): @@ -169,13 +181,18 @@ def test_intents_client_from_service_account_file(client_class, transport_name): assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_intents_client_get_transport_class(): transport = IntentsClient.get_transport_class() available_transports = [ transports.IntentsGrpcTransport, + transports.IntentsRestTransport, ] assert transport in available_transports @@ -188,6 +205,7 @@ def test_intents_client_get_transport_class(): [ (IntentsClient, transports.IntentsGrpcTransport, "grpc"), (IntentsAsyncClient, transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (IntentsClient, transports.IntentsRestTransport, "rest"), ], ) @mock.patch.object( @@ -327,6 +345,8 @@ def test_intents_client_client_options(client_class, transport_class, transport_ "grpc_asyncio", "false", ), + (IntentsClient, transports.IntentsRestTransport, "rest", "true"), + (IntentsClient, transports.IntentsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -512,6 +532,7 @@ def test_intents_client_get_mtls_endpoint_and_cert_source(client_class): [ (IntentsClient, transports.IntentsGrpcTransport, "grpc"), (IntentsAsyncClient, transports.IntentsGrpcAsyncIOTransport, "grpc_asyncio"), + (IntentsClient, transports.IntentsRestTransport, "rest"), ], ) def test_intents_client_client_options_scopes( @@ -547,6 +568,7 @@ def test_intents_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (IntentsClient, transports.IntentsRestTransport, "rest", None), ], ) def test_intents_client_client_options_credentials_file( @@ -2755,257 +2777,3138 @@ async def test_batch_delete_intents_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.IntentsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + intent.ListIntentsRequest, + dict, + ], +) +def test_list_intents_rest(request_type): + client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = IntentsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.IntentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = IntentsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.IntentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = IntentsClient( - client_options=options, - transport=transport, + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = intent.ListIntentsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = IntentsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.ListIntentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.IntentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = IntentsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_intents(request) + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListIntentsPager) + assert response.next_page_token == "next_page_token_value" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.IntentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - client = IntentsClient(transport=transport) - assert client.transport is transport +def test_list_intents_rest_required_fields(request_type=intent.ListIntentsRequest): + transport_class = transports.IntentsRestTransport -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.IntentsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - channel = transport.grpc_channel - assert channel - transport = transports.IntentsGrpcAsyncIOTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - channel = transport.grpc_channel - assert channel + # verify fields with default values are dropped + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_intents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) -@pytest.mark.parametrize( - "transport_class", - [ - transports.IntentsGrpcTransport, - transports.IntentsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + # verify required fields with default values are now present + jsonified_request["parent"] = "parent_value" -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = IntentsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_intents._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "intent_view", + "language_code", + "page_size", + "page_token", + ) ) - assert transport.kind == transport_name + jsonified_request.update(unset_fields) + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = intent.ListIntentsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = intent.ListIntentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_intents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_intents_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.IntentsGrpcTransport, + + unset_fields = transport.list_intents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "intentView", + "languageCode", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) ) -def test_intents_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.IntentsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_intents_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.IntentsRestInterceptor, "post_list_intents" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_list_intents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.ListIntentsRequest.pb(intent.ListIntentsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = intent.ListIntentsResponse.to_json( + intent.ListIntentsResponse() ) + request = intent.ListIntentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = intent.ListIntentsResponse() -def test_intents_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2beta1.services.intents.transports.IntentsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.IntentsTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_intents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_intents", - "get_intent", - "create_intent", - "update_intent", - "delete_intent", - "batch_update_intents", - "batch_delete_intents", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) + pre.assert_called_once() + post.assert_called_once() - with pytest.raises(NotImplementedError): - transport.close() - # Additionally, the LRO client (a property) should - # also raise NotImplementedError - with pytest.raises(NotImplementedError): - transport.operations_client +def test_list_intents_rest_bad_request( + transport: str = "rest", request_type=intent.ListIntentsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_intents(request) -def test_intents_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.dialogflow_v2beta1.services.intents.transports.IntentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.IntentsTransport( - credentials_file="credentials.json", - quota_project_id="octopus", - ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", - ) +def test_list_intents_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) -def test_intents_base_transport_with_adc(): - # Test the default credentials are used if credentials and credentials_file are None. - with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( - "google.cloud.dialogflow_v2beta1.services.intents.transports.IntentsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.IntentsTransport() - adc.assert_called_once() + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = intent.ListIntentsResponse() + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} -def test_intents_auth_adc(): - # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - IntentsClient() - adc.assert_called_once_with( - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id=None, + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + language_code="language_code_value", ) + mock_args.update(sample_request) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.ListIntentsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value -@pytest.mark.parametrize( - "transport_class", - [ - transports.IntentsGrpcTransport, - transports.IntentsGrpcAsyncIOTransport, - ], -) -def test_intents_transport_auth_adc(transport_class): - # If credentials and host are not provided, the transport class should use - # ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class(quota_project_id="octopus", scopes=["1", "2"]) - adc.assert_called_once_with( - scopes=["1", "2"], - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", + client.list_intents(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent}/intents" % client.transport._host, + args[1], ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.IntentsGrpcTransport, - transports.IntentsGrpcAsyncIOTransport, - ], -) +def test_list_intents_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_intents( + intent.ListIntentsRequest(), + parent="parent_value", + language_code="language_code_value", + ) + + +def test_list_intents_rest_pager(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + intent.Intent(), + intent.Intent(), + ], + next_page_token="abc", + ), + intent.ListIntentsResponse( + intents=[], + next_page_token="def", + ), + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + ], + next_page_token="ghi", + ), + intent.ListIntentsResponse( + intents=[ + intent.Intent(), + intent.Intent(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(intent.ListIntentsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/agent"} + + pager = client.list_intents(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, intent.Intent) for i in results) + + pages = list(client.list_intents(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + intent.GetIntentRequest, + dict, + ], +) +def test_get_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/intents/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = intent.Intent( + name="name_value", + display_name="display_name_value", + webhook_state=intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED, + priority=898, + is_fallback=True, + ml_enabled=True, + ml_disabled=True, + live_agent_handoff=True, + end_interaction=True, + input_context_names=["input_context_names_value"], + events=["events_value"], + action="action_value", + reset_contexts=True, + default_response_platforms=[intent.Intent.Message.Platform.FACEBOOK], + root_followup_intent_name="root_followup_intent_name_value", + parent_followup_intent_name="parent_followup_intent_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.webhook_state == intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED + assert response.priority == 898 + assert response.is_fallback is True + assert response.ml_enabled is True + assert response.ml_disabled is True + assert response.live_agent_handoff is True + assert response.end_interaction is True + assert response.input_context_names == ["input_context_names_value"] + assert response.events == ["events_value"] + assert response.action == "action_value" + assert response.reset_contexts is True + assert response.default_response_platforms == [ + intent.Intent.Message.Platform.FACEBOOK + ] + assert response.root_followup_intent_name == "root_followup_intent_name_value" + assert response.parent_followup_intent_name == "parent_followup_intent_name_value" + + +def test_get_intent_rest_required_fields(request_type=intent.GetIntentRequest): + transport_class = transports.IntentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "intent_view", + "language_code", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = intent.Intent() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "intentView", + "languageCode", + ) + ) + & set(("name",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.IntentsRestInterceptor, "post_get_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_get_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.GetIntentRequest.pb(intent.GetIntentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = intent.Intent.to_json(intent.Intent()) + + request = intent.GetIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = intent.Intent() + + client.get_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_intent_rest_bad_request( + transport: str = "rest", request_type=intent.GetIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/intents/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_intent(request) + + +def test_get_intent_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/intents/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_intent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/agent/intents/*}" % client.transport._host, + args[1], + ) + + +def test_get_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_intent( + intent.GetIntentRequest(), + name="name_value", + language_code="language_code_value", + ) + + +def test_get_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_intent.CreateIntentRequest, + dict, + ], +) +def test_create_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["intent"] = { + "name": "name_value", + "display_name": "display_name_value", + "webhook_state": 1, + "priority": 898, + "is_fallback": True, + "ml_enabled": True, + "ml_disabled": True, + "live_agent_handoff": True, + "end_interaction": True, + "input_context_names": [ + "input_context_names_value1", + "input_context_names_value2", + ], + "events": ["events_value1", "events_value2"], + "training_phrases": [ + { + "name": "name_value", + "type_": 1, + "parts": [ + { + "text": "text_value", + "entity_type": "entity_type_value", + "alias": "alias_value", + "user_defined": True, + } + ], + "times_added_count": 1787, + } + ], + "action": "action_value", + "output_contexts": [ + {"name": "name_value", "lifespan_count": 1498, "parameters": {"fields": {}}} + ], + "reset_contexts": True, + "parameters": [ + { + "name": "name_value", + "display_name": "display_name_value", + "value": "value_value", + "default_value": "default_value_value", + "entity_type_display_name": "entity_type_display_name_value", + "mandatory": True, + "prompts": ["prompts_value1", "prompts_value2"], + "is_list": True, + } + ], + "messages": [ + { + "text": {"text": ["text_value1", "text_value2"]}, + "image": { + "image_uri": "image_uri_value", + "accessibility_text": "accessibility_text_value", + }, + "quick_replies": { + "title": "title_value", + "quick_replies": ["quick_replies_value1", "quick_replies_value2"], + }, + "card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image_uri": "image_uri_value", + "buttons": [{"text": "text_value", "postback": "postback_value"}], + }, + "payload": {}, + "simple_responses": { + "simple_responses": [ + { + "text_to_speech": "text_to_speech_value", + "ssml": "ssml_value", + "display_text": "display_text_value", + } + ] + }, + "basic_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "formatted_text": "formatted_text_value", + "image": {}, + "buttons": [ + { + "title": "title_value", + "open_uri_action": {"uri": "uri_value"}, + } + ], + }, + "suggestions": {"suggestions": [{"title": "title_value"}]}, + "link_out_suggestion": { + "destination_name": "destination_name_value", + "uri": "uri_value", + }, + "list_select": { + "title": "title_value", + "items": [ + { + "info": { + "key": "key_value", + "synonyms": ["synonyms_value1", "synonyms_value2"], + }, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ], + "subtitle": "subtitle_value", + }, + "carousel_select": { + "items": [ + { + "info": {}, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ] + }, + "telephony_play_audio": {"audio_uri": "audio_uri_value"}, + "telephony_synthesize_speech": { + "text": "text_value", + "ssml": "ssml_value", + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "rbm_text": { + "text": "text_value", + "rbm_suggestion": [ + { + "reply": { + "text": "text_value", + "postback_data": "postback_data_value", + }, + "action": { + "text": "text_value", + "postback_data": "postback_data_value", + "dial": {"phone_number": "phone_number_value"}, + "open_url": {"uri": "uri_value"}, + "share_location": {}, + }, + } + ], + }, + "rbm_standalone_rich_card": { + "card_orientation": 1, + "thumbnail_image_alignment": 1, + "card_content": { + "title": "title_value", + "description": "description_value", + "media": { + "file_uri": "file_uri_value", + "thumbnail_uri": "thumbnail_uri_value", + "height": 1, + }, + "suggestions": {}, + }, + }, + "rbm_carousel_rich_card": {"card_width": 1, "card_contents": {}}, + "browse_carousel_card": { + "items": [ + { + "open_uri_action": {"url": "url_value", "url_type_hint": 1}, + "title": "title_value", + "description": "description_value", + "image": {}, + "footer": "footer_value", + } + ], + "image_display_options": 1, + }, + "table_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image": {}, + "column_properties": [ + {"header": "header_value", "horizontal_alignment": 1} + ], + "rows": [ + {"cells": [{"text": "text_value"}], "divider_after": True} + ], + "buttons": {}, + }, + "media_content": { + "media_type": 1, + "media_objects": [ + { + "name": "name_value", + "description": "description_value", + "large_image": {}, + "icon": {}, + "content_url": "content_url_value", + } + ], + }, + "platform": 1, + } + ], + "default_response_platforms": [1], + "root_followup_intent_name": "root_followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + "followup_intent_info": [ + { + "followup_intent_name": "followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + } + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent( + name="name_value", + display_name="display_name_value", + webhook_state=gcd_intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED, + priority=898, + is_fallback=True, + ml_enabled=True, + ml_disabled=True, + live_agent_handoff=True, + end_interaction=True, + input_context_names=["input_context_names_value"], + events=["events_value"], + action="action_value", + reset_contexts=True, + default_response_platforms=[gcd_intent.Intent.Message.Platform.FACEBOOK], + root_followup_intent_name="root_followup_intent_name_value", + parent_followup_intent_name="parent_followup_intent_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert ( + response.webhook_state == gcd_intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED + ) + assert response.priority == 898 + assert response.is_fallback is True + assert response.ml_enabled is True + assert response.ml_disabled is True + assert response.live_agent_handoff is True + assert response.end_interaction is True + assert response.input_context_names == ["input_context_names_value"] + assert response.events == ["events_value"] + assert response.action == "action_value" + assert response.reset_contexts is True + assert response.default_response_platforms == [ + gcd_intent.Intent.Message.Platform.FACEBOOK + ] + assert response.root_followup_intent_name == "root_followup_intent_name_value" + assert response.parent_followup_intent_name == "parent_followup_intent_name_value" + + +def test_create_intent_rest_required_fields( + request_type=gcd_intent.CreateIntentRequest, +): + transport_class = transports.IntentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "intent_view", + "language_code", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "intentView", + "languageCode", + ) + ) + & set( + ( + "parent", + "intent", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.IntentsRestInterceptor, "post_create_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_create_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_intent.CreateIntentRequest.pb(gcd_intent.CreateIntentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_intent.Intent.to_json(gcd_intent.Intent()) + + request = gcd_intent.CreateIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_intent.Intent() + + client.create_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_intent_rest_bad_request( + transport: str = "rest", request_type=gcd_intent.CreateIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["intent"] = { + "name": "name_value", + "display_name": "display_name_value", + "webhook_state": 1, + "priority": 898, + "is_fallback": True, + "ml_enabled": True, + "ml_disabled": True, + "live_agent_handoff": True, + "end_interaction": True, + "input_context_names": [ + "input_context_names_value1", + "input_context_names_value2", + ], + "events": ["events_value1", "events_value2"], + "training_phrases": [ + { + "name": "name_value", + "type_": 1, + "parts": [ + { + "text": "text_value", + "entity_type": "entity_type_value", + "alias": "alias_value", + "user_defined": True, + } + ], + "times_added_count": 1787, + } + ], + "action": "action_value", + "output_contexts": [ + {"name": "name_value", "lifespan_count": 1498, "parameters": {"fields": {}}} + ], + "reset_contexts": True, + "parameters": [ + { + "name": "name_value", + "display_name": "display_name_value", + "value": "value_value", + "default_value": "default_value_value", + "entity_type_display_name": "entity_type_display_name_value", + "mandatory": True, + "prompts": ["prompts_value1", "prompts_value2"], + "is_list": True, + } + ], + "messages": [ + { + "text": {"text": ["text_value1", "text_value2"]}, + "image": { + "image_uri": "image_uri_value", + "accessibility_text": "accessibility_text_value", + }, + "quick_replies": { + "title": "title_value", + "quick_replies": ["quick_replies_value1", "quick_replies_value2"], + }, + "card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image_uri": "image_uri_value", + "buttons": [{"text": "text_value", "postback": "postback_value"}], + }, + "payload": {}, + "simple_responses": { + "simple_responses": [ + { + "text_to_speech": "text_to_speech_value", + "ssml": "ssml_value", + "display_text": "display_text_value", + } + ] + }, + "basic_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "formatted_text": "formatted_text_value", + "image": {}, + "buttons": [ + { + "title": "title_value", + "open_uri_action": {"uri": "uri_value"}, + } + ], + }, + "suggestions": {"suggestions": [{"title": "title_value"}]}, + "link_out_suggestion": { + "destination_name": "destination_name_value", + "uri": "uri_value", + }, + "list_select": { + "title": "title_value", + "items": [ + { + "info": { + "key": "key_value", + "synonyms": ["synonyms_value1", "synonyms_value2"], + }, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ], + "subtitle": "subtitle_value", + }, + "carousel_select": { + "items": [ + { + "info": {}, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ] + }, + "telephony_play_audio": {"audio_uri": "audio_uri_value"}, + "telephony_synthesize_speech": { + "text": "text_value", + "ssml": "ssml_value", + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "rbm_text": { + "text": "text_value", + "rbm_suggestion": [ + { + "reply": { + "text": "text_value", + "postback_data": "postback_data_value", + }, + "action": { + "text": "text_value", + "postback_data": "postback_data_value", + "dial": {"phone_number": "phone_number_value"}, + "open_url": {"uri": "uri_value"}, + "share_location": {}, + }, + } + ], + }, + "rbm_standalone_rich_card": { + "card_orientation": 1, + "thumbnail_image_alignment": 1, + "card_content": { + "title": "title_value", + "description": "description_value", + "media": { + "file_uri": "file_uri_value", + "thumbnail_uri": "thumbnail_uri_value", + "height": 1, + }, + "suggestions": {}, + }, + }, + "rbm_carousel_rich_card": {"card_width": 1, "card_contents": {}}, + "browse_carousel_card": { + "items": [ + { + "open_uri_action": {"url": "url_value", "url_type_hint": 1}, + "title": "title_value", + "description": "description_value", + "image": {}, + "footer": "footer_value", + } + ], + "image_display_options": 1, + }, + "table_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image": {}, + "column_properties": [ + {"header": "header_value", "horizontal_alignment": 1} + ], + "rows": [ + {"cells": [{"text": "text_value"}], "divider_after": True} + ], + "buttons": {}, + }, + "media_content": { + "media_type": 1, + "media_objects": [ + { + "name": "name_value", + "description": "description_value", + "large_image": {}, + "icon": {}, + "content_url": "content_url_value", + } + ], + }, + "platform": 1, + } + ], + "default_response_platforms": [1], + "root_followup_intent_name": "root_followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + "followup_intent_info": [ + { + "followup_intent_name": "followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + } + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_intent(request) + + +def test_create_intent_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + intent=gcd_intent.Intent(name="name_value"), + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_intent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent}/intents" % client.transport._host, + args[1], + ) + + +def test_create_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_intent( + gcd_intent.CreateIntentRequest(), + parent="parent_value", + intent=gcd_intent.Intent(name="name_value"), + language_code="language_code_value", + ) + + +def test_create_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_intent.UpdateIntentRequest, + dict, + ], +) +def test_update_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"intent": {"name": "projects/sample1/agent/intents/sample2"}} + request_init["intent"] = { + "name": "projects/sample1/agent/intents/sample2", + "display_name": "display_name_value", + "webhook_state": 1, + "priority": 898, + "is_fallback": True, + "ml_enabled": True, + "ml_disabled": True, + "live_agent_handoff": True, + "end_interaction": True, + "input_context_names": [ + "input_context_names_value1", + "input_context_names_value2", + ], + "events": ["events_value1", "events_value2"], + "training_phrases": [ + { + "name": "name_value", + "type_": 1, + "parts": [ + { + "text": "text_value", + "entity_type": "entity_type_value", + "alias": "alias_value", + "user_defined": True, + } + ], + "times_added_count": 1787, + } + ], + "action": "action_value", + "output_contexts": [ + {"name": "name_value", "lifespan_count": 1498, "parameters": {"fields": {}}} + ], + "reset_contexts": True, + "parameters": [ + { + "name": "name_value", + "display_name": "display_name_value", + "value": "value_value", + "default_value": "default_value_value", + "entity_type_display_name": "entity_type_display_name_value", + "mandatory": True, + "prompts": ["prompts_value1", "prompts_value2"], + "is_list": True, + } + ], + "messages": [ + { + "text": {"text": ["text_value1", "text_value2"]}, + "image": { + "image_uri": "image_uri_value", + "accessibility_text": "accessibility_text_value", + }, + "quick_replies": { + "title": "title_value", + "quick_replies": ["quick_replies_value1", "quick_replies_value2"], + }, + "card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image_uri": "image_uri_value", + "buttons": [{"text": "text_value", "postback": "postback_value"}], + }, + "payload": {}, + "simple_responses": { + "simple_responses": [ + { + "text_to_speech": "text_to_speech_value", + "ssml": "ssml_value", + "display_text": "display_text_value", + } + ] + }, + "basic_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "formatted_text": "formatted_text_value", + "image": {}, + "buttons": [ + { + "title": "title_value", + "open_uri_action": {"uri": "uri_value"}, + } + ], + }, + "suggestions": {"suggestions": [{"title": "title_value"}]}, + "link_out_suggestion": { + "destination_name": "destination_name_value", + "uri": "uri_value", + }, + "list_select": { + "title": "title_value", + "items": [ + { + "info": { + "key": "key_value", + "synonyms": ["synonyms_value1", "synonyms_value2"], + }, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ], + "subtitle": "subtitle_value", + }, + "carousel_select": { + "items": [ + { + "info": {}, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ] + }, + "telephony_play_audio": {"audio_uri": "audio_uri_value"}, + "telephony_synthesize_speech": { + "text": "text_value", + "ssml": "ssml_value", + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "rbm_text": { + "text": "text_value", + "rbm_suggestion": [ + { + "reply": { + "text": "text_value", + "postback_data": "postback_data_value", + }, + "action": { + "text": "text_value", + "postback_data": "postback_data_value", + "dial": {"phone_number": "phone_number_value"}, + "open_url": {"uri": "uri_value"}, + "share_location": {}, + }, + } + ], + }, + "rbm_standalone_rich_card": { + "card_orientation": 1, + "thumbnail_image_alignment": 1, + "card_content": { + "title": "title_value", + "description": "description_value", + "media": { + "file_uri": "file_uri_value", + "thumbnail_uri": "thumbnail_uri_value", + "height": 1, + }, + "suggestions": {}, + }, + }, + "rbm_carousel_rich_card": {"card_width": 1, "card_contents": {}}, + "browse_carousel_card": { + "items": [ + { + "open_uri_action": {"url": "url_value", "url_type_hint": 1}, + "title": "title_value", + "description": "description_value", + "image": {}, + "footer": "footer_value", + } + ], + "image_display_options": 1, + }, + "table_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image": {}, + "column_properties": [ + {"header": "header_value", "horizontal_alignment": 1} + ], + "rows": [ + {"cells": [{"text": "text_value"}], "divider_after": True} + ], + "buttons": {}, + }, + "media_content": { + "media_type": 1, + "media_objects": [ + { + "name": "name_value", + "description": "description_value", + "large_image": {}, + "icon": {}, + "content_url": "content_url_value", + } + ], + }, + "platform": 1, + } + ], + "default_response_platforms": [1], + "root_followup_intent_name": "root_followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + "followup_intent_info": [ + { + "followup_intent_name": "followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + } + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent( + name="name_value", + display_name="display_name_value", + webhook_state=gcd_intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED, + priority=898, + is_fallback=True, + ml_enabled=True, + ml_disabled=True, + live_agent_handoff=True, + end_interaction=True, + input_context_names=["input_context_names_value"], + events=["events_value"], + action="action_value", + reset_contexts=True, + default_response_platforms=[gcd_intent.Intent.Message.Platform.FACEBOOK], + root_followup_intent_name="root_followup_intent_name_value", + parent_followup_intent_name="parent_followup_intent_name_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_intent.Intent) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert ( + response.webhook_state == gcd_intent.Intent.WebhookState.WEBHOOK_STATE_ENABLED + ) + assert response.priority == 898 + assert response.is_fallback is True + assert response.ml_enabled is True + assert response.ml_disabled is True + assert response.live_agent_handoff is True + assert response.end_interaction is True + assert response.input_context_names == ["input_context_names_value"] + assert response.events == ["events_value"] + assert response.action == "action_value" + assert response.reset_contexts is True + assert response.default_response_platforms == [ + gcd_intent.Intent.Message.Platform.FACEBOOK + ] + assert response.root_followup_intent_name == "root_followup_intent_name_value" + assert response.parent_followup_intent_name == "parent_followup_intent_name_value" + + +def test_update_intent_rest_required_fields( + request_type=gcd_intent.UpdateIntentRequest, +): + transport_class = transports.IntentsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_intent._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "intent_view", + "language_code", + "update_mask", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "intentView", + "languageCode", + "updateMask", + ) + ) + & set(("intent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.IntentsRestInterceptor, "post_update_intent" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_update_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_intent.UpdateIntentRequest.pb(gcd_intent.UpdateIntentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_intent.Intent.to_json(gcd_intent.Intent()) + + request = gcd_intent.UpdateIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_intent.Intent() + + client.update_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_intent_rest_bad_request( + transport: str = "rest", request_type=gcd_intent.UpdateIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"intent": {"name": "projects/sample1/agent/intents/sample2"}} + request_init["intent"] = { + "name": "projects/sample1/agent/intents/sample2", + "display_name": "display_name_value", + "webhook_state": 1, + "priority": 898, + "is_fallback": True, + "ml_enabled": True, + "ml_disabled": True, + "live_agent_handoff": True, + "end_interaction": True, + "input_context_names": [ + "input_context_names_value1", + "input_context_names_value2", + ], + "events": ["events_value1", "events_value2"], + "training_phrases": [ + { + "name": "name_value", + "type_": 1, + "parts": [ + { + "text": "text_value", + "entity_type": "entity_type_value", + "alias": "alias_value", + "user_defined": True, + } + ], + "times_added_count": 1787, + } + ], + "action": "action_value", + "output_contexts": [ + {"name": "name_value", "lifespan_count": 1498, "parameters": {"fields": {}}} + ], + "reset_contexts": True, + "parameters": [ + { + "name": "name_value", + "display_name": "display_name_value", + "value": "value_value", + "default_value": "default_value_value", + "entity_type_display_name": "entity_type_display_name_value", + "mandatory": True, + "prompts": ["prompts_value1", "prompts_value2"], + "is_list": True, + } + ], + "messages": [ + { + "text": {"text": ["text_value1", "text_value2"]}, + "image": { + "image_uri": "image_uri_value", + "accessibility_text": "accessibility_text_value", + }, + "quick_replies": { + "title": "title_value", + "quick_replies": ["quick_replies_value1", "quick_replies_value2"], + }, + "card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image_uri": "image_uri_value", + "buttons": [{"text": "text_value", "postback": "postback_value"}], + }, + "payload": {}, + "simple_responses": { + "simple_responses": [ + { + "text_to_speech": "text_to_speech_value", + "ssml": "ssml_value", + "display_text": "display_text_value", + } + ] + }, + "basic_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "formatted_text": "formatted_text_value", + "image": {}, + "buttons": [ + { + "title": "title_value", + "open_uri_action": {"uri": "uri_value"}, + } + ], + }, + "suggestions": {"suggestions": [{"title": "title_value"}]}, + "link_out_suggestion": { + "destination_name": "destination_name_value", + "uri": "uri_value", + }, + "list_select": { + "title": "title_value", + "items": [ + { + "info": { + "key": "key_value", + "synonyms": ["synonyms_value1", "synonyms_value2"], + }, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ], + "subtitle": "subtitle_value", + }, + "carousel_select": { + "items": [ + { + "info": {}, + "title": "title_value", + "description": "description_value", + "image": {}, + } + ] + }, + "telephony_play_audio": {"audio_uri": "audio_uri_value"}, + "telephony_synthesize_speech": { + "text": "text_value", + "ssml": "ssml_value", + }, + "telephony_transfer_call": {"phone_number": "phone_number_value"}, + "rbm_text": { + "text": "text_value", + "rbm_suggestion": [ + { + "reply": { + "text": "text_value", + "postback_data": "postback_data_value", + }, + "action": { + "text": "text_value", + "postback_data": "postback_data_value", + "dial": {"phone_number": "phone_number_value"}, + "open_url": {"uri": "uri_value"}, + "share_location": {}, + }, + } + ], + }, + "rbm_standalone_rich_card": { + "card_orientation": 1, + "thumbnail_image_alignment": 1, + "card_content": { + "title": "title_value", + "description": "description_value", + "media": { + "file_uri": "file_uri_value", + "thumbnail_uri": "thumbnail_uri_value", + "height": 1, + }, + "suggestions": {}, + }, + }, + "rbm_carousel_rich_card": {"card_width": 1, "card_contents": {}}, + "browse_carousel_card": { + "items": [ + { + "open_uri_action": {"url": "url_value", "url_type_hint": 1}, + "title": "title_value", + "description": "description_value", + "image": {}, + "footer": "footer_value", + } + ], + "image_display_options": 1, + }, + "table_card": { + "title": "title_value", + "subtitle": "subtitle_value", + "image": {}, + "column_properties": [ + {"header": "header_value", "horizontal_alignment": 1} + ], + "rows": [ + {"cells": [{"text": "text_value"}], "divider_after": True} + ], + "buttons": {}, + }, + "media_content": { + "media_type": 1, + "media_objects": [ + { + "name": "name_value", + "description": "description_value", + "large_image": {}, + "icon": {}, + "content_url": "content_url_value", + } + ], + }, + "platform": 1, + } + ], + "default_response_platforms": [1], + "root_followup_intent_name": "root_followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + "followup_intent_info": [ + { + "followup_intent_name": "followup_intent_name_value", + "parent_followup_intent_name": "parent_followup_intent_name_value", + } + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_intent(request) + + +def test_update_intent_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_intent.Intent() + + # get arguments that satisfy an http rule for this method + sample_request = {"intent": {"name": "projects/sample1/agent/intents/sample2"}} + + # get truthy value for each flattened field + mock_args = dict( + intent=gcd_intent.Intent(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + language_code="language_code_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_intent.Intent.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_intent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{intent.name=projects/*/agent/intents/*}" + % client.transport._host, + args[1], + ) + + +def test_update_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_intent( + gcd_intent.UpdateIntentRequest(), + intent=gcd_intent.Intent(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + language_code="language_code_value", + ) + + +def test_update_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + intent.DeleteIntentRequest, + dict, + ], +) +def test_delete_intent_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/intents/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_intent(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_intent_rest_required_fields(request_type=intent.DeleteIntentRequest): + transport_class = transports.IntentsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_intent_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_intent._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_intent_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.IntentsRestInterceptor, "pre_delete_intent" + ) as pre: + pre.assert_not_called() + pb_message = intent.DeleteIntentRequest.pb(intent.DeleteIntentRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = intent.DeleteIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_intent_rest_bad_request( + transport: str = "rest", request_type=intent.DeleteIntentRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/intents/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_intent(request) + + +def test_delete_intent_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/intents/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_intent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/agent/intents/*}" % client.transport._host, + args[1], + ) + + +def test_delete_intent_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_intent( + intent.DeleteIntentRequest(), + name="name_value", + ) + + +def test_delete_intent_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + intent.BatchUpdateIntentsRequest, + dict, + ], +) +def test_batch_update_intents_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_update_intents(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_update_intents_rest_required_fields( + request_type=intent.BatchUpdateIntentsRequest, +): + transport_class = transports.IntentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_intents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_update_intents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_update_intents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_update_intents_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_update_intents._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_update_intents_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.IntentsRestInterceptor, "post_batch_update_intents" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_batch_update_intents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.BatchUpdateIntentsRequest.pb( + intent.BatchUpdateIntentsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = intent.BatchUpdateIntentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_update_intents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_update_intents_rest_bad_request( + transport: str = "rest", request_type=intent.BatchUpdateIntentsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_update_intents(request) + + +def test_batch_update_intents_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_update_intents(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent}/intents:batchUpdate" + % client.transport._host, + args[1], + ) + + +def test_batch_update_intents_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_update_intents( + intent.BatchUpdateIntentsRequest(), + parent="parent_value", + intent_batch_uri="intent_batch_uri_value", + intent_batch_inline=intent.IntentBatch( + intents=[intent.Intent(name="name_value")] + ), + ) + + +def test_batch_update_intents_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + intent.BatchDeleteIntentsRequest, + dict, + ], +) +def test_batch_delete_intents_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.batch_delete_intents(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_batch_delete_intents_rest_required_fields( + request_type=intent.BatchDeleteIntentsRequest, +): + transport_class = transports.IntentsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_intents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).batch_delete_intents._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.batch_delete_intents(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_batch_delete_intents_rest_unset_required_fields(): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.batch_delete_intents._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "intents", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_batch_delete_intents_rest_interceptors(null_interceptor): + transport = transports.IntentsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.IntentsRestInterceptor(), + ) + client = IntentsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.IntentsRestInterceptor, "post_batch_delete_intents" + ) as post, mock.patch.object( + transports.IntentsRestInterceptor, "pre_batch_delete_intents" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = intent.BatchDeleteIntentsRequest.pb( + intent.BatchDeleteIntentsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) + + request = intent.BatchDeleteIntentsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.batch_delete_intents( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_batch_delete_intents_rest_bad_request( + transport: str = "rest", request_type=intent.BatchDeleteIntentsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.batch_delete_intents(request) + + +def test_batch_delete_intents_rest_flattened(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + intents=[intent.Intent(name="name_value")], + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.batch_delete_intents(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent}/intents:batchDelete" + % client.transport._host, + args[1], + ) + + +def test_batch_delete_intents_rest_flattened_error(transport: str = "rest"): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_delete_intents( + intent.BatchDeleteIntentsRequest(), + parent="parent_value", + intents=[intent.Intent(name="name_value")], + ) + + +def test_batch_delete_intents_rest_error(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = IntentsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = IntentsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = IntentsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = IntentsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.IntentsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.IntentsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.IntentsGrpcTransport, + transports.IntentsGrpcAsyncIOTransport, + transports.IntentsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = IntentsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.IntentsGrpcTransport, + ) + + +def test_intents_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.IntentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_intents_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2beta1.services.intents.transports.IntentsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.IntentsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_intents", + "get_intent", + "create_intent", + "update_intent", + "delete_intent", + "batch_update_intents", + "batch_delete_intents", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_intents_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.dialogflow_v2beta1.services.intents.transports.IntentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.IntentsTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_intents_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.dialogflow_v2beta1.services.intents.transports.IntentsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.IntentsTransport() + adc.assert_called_once() + + +def test_intents_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + IntentsClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.IntentsGrpcTransport, + transports.IntentsGrpcAsyncIOTransport, + ], +) +def test_intents_transport_auth_adc(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.IntentsGrpcTransport, + transports.IntentsGrpcAsyncIOTransport, + transports.IntentsRestTransport, + ], +) def test_intents_transport_auth_gdch_credentials(transport_class): host = "https://language.com" api_audience_tests = [None, "https://language2.com"] @@ -3101,11 +6004,40 @@ def test_intents_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_intents_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.IntentsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + +def test_intents_rest_lro_client(): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance( + transport.operations_client, + operations_v1.AbstractOperationsClient, + ) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_intents_host_no_port(transport_name): @@ -3116,7 +6048,11 @@ def test_intents_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3124,6 +6060,7 @@ def test_intents_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_intents_host_with_port(transport_name): @@ -3134,7 +6071,51 @@ def test_intents_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_intents_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = IntentsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = IntentsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_intents._session + session2 = client2.transport.list_intents._session + assert session1 != session2 + session1 = client1.transport.get_intent._session + session2 = client2.transport.get_intent._session + assert session1 != session2 + session1 = client1.transport.create_intent._session + session2 = client2.transport.create_intent._session + assert session1 != session2 + session1 = client1.transport.update_intent._session + session2 = client2.transport.update_intent._session + assert session1 != session2 + session1 = client1.transport.delete_intent._session + session2 = client2.transport.delete_intent._session + assert session1 != session2 + session1 = client1.transport.batch_update_intents._session + session2 = client2.transport.batch_update_intents._session + assert session1 != session2 + session1 = client1.transport.batch_delete_intents._session + session2 = client2.transport.batch_delete_intents._session + assert session1 != session2 def test_intents_grpc_transport_channel(): @@ -3478,6 +6459,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = IntentsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = IntentsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4195,6 +7462,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -4212,6 +7480,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_knowledge_bases.py b/tests/unit/gapic/dialogflow_v2beta1/test_knowledge_bases.py index 78f8186e7..db99c5039 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_knowledge_bases.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_knowledge_bases.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,11 +36,14 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.knowledge_bases import ( KnowledgeBasesAsyncClient, @@ -99,6 +104,7 @@ def test__get_default_mtls_endpoint(): [ (KnowledgeBasesClient, "grpc"), (KnowledgeBasesAsyncClient, "grpc_asyncio"), + (KnowledgeBasesClient, "rest"), ], ) def test_knowledge_bases_client_from_service_account_info(client_class, transport_name): @@ -112,7 +118,11 @@ def test_knowledge_bases_client_from_service_account_info(client_class, transpor assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -120,6 +130,7 @@ def test_knowledge_bases_client_from_service_account_info(client_class, transpor [ (transports.KnowledgeBasesGrpcTransport, "grpc"), (transports.KnowledgeBasesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.KnowledgeBasesRestTransport, "rest"), ], ) def test_knowledge_bases_client_service_account_always_use_jwt( @@ -145,6 +156,7 @@ def test_knowledge_bases_client_service_account_always_use_jwt( [ (KnowledgeBasesClient, "grpc"), (KnowledgeBasesAsyncClient, "grpc_asyncio"), + (KnowledgeBasesClient, "rest"), ], ) def test_knowledge_bases_client_from_service_account_file(client_class, transport_name): @@ -165,13 +177,18 @@ def test_knowledge_bases_client_from_service_account_file(client_class, transpor assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_knowledge_bases_client_get_transport_class(): transport = KnowledgeBasesClient.get_transport_class() available_transports = [ transports.KnowledgeBasesGrpcTransport, + transports.KnowledgeBasesRestTransport, ] assert transport in available_transports @@ -188,6 +205,7 @@ def test_knowledge_bases_client_get_transport_class(): transports.KnowledgeBasesGrpcAsyncIOTransport, "grpc_asyncio", ), + (KnowledgeBasesClient, transports.KnowledgeBasesRestTransport, "rest"), ], ) @mock.patch.object( @@ -333,6 +351,8 @@ def test_knowledge_bases_client_client_options( "grpc_asyncio", "false", ), + (KnowledgeBasesClient, transports.KnowledgeBasesRestTransport, "rest", "true"), + (KnowledgeBasesClient, transports.KnowledgeBasesRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -532,6 +552,7 @@ def test_knowledge_bases_client_get_mtls_endpoint_and_cert_source(client_class): transports.KnowledgeBasesGrpcAsyncIOTransport, "grpc_asyncio", ), + (KnowledgeBasesClient, transports.KnowledgeBasesRestTransport, "rest"), ], ) def test_knowledge_bases_client_client_options_scopes( @@ -572,6 +593,7 @@ def test_knowledge_bases_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (KnowledgeBasesClient, transports.KnowledgeBasesRestTransport, "rest", None), ], ) def test_knowledge_bases_client_client_options_credentials_file( @@ -2149,208 +2171,1656 @@ async def test_update_knowledge_base_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.KnowledgeBasesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + knowledge_base.ListKnowledgeBasesRequest, + dict, + ], +) +def test_list_knowledge_bases_rest(request_type): + client = KnowledgeBasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = KnowledgeBasesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.KnowledgeBasesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = KnowledgeBasesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.KnowledgeBasesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = KnowledgeBasesClient( - client_options=options, - transport=transport, + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = knowledge_base.ListKnowledgeBasesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = KnowledgeBasesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() - ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = knowledge_base.ListKnowledgeBasesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.KnowledgeBasesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_knowledge_bases(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListKnowledgeBasesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_knowledge_bases_rest_required_fields( + request_type=knowledge_base.ListKnowledgeBasesRequest, +): + transport_class = transports.KnowledgeBasesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - with pytest.raises(ValueError): - client = KnowledgeBasesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_knowledge_bases._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_knowledge_bases._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "filter", + "page_size", + "page_token", ) + ) + jsonified_request.update(unset_fields) + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.KnowledgeBasesGrpcTransport( + client = KnowledgeBasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = KnowledgeBasesClient(transport=transport) - assert client.transport is transport + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = knowledge_base.ListKnowledgeBasesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + response_value = Response() + response_value.status_code = 200 -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.KnowledgeBasesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + pb_return_value = knowledge_base.ListKnowledgeBasesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_knowledge_bases(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_knowledge_bases_rest_unset_required_fields(): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - channel = transport.grpc_channel - assert channel - transport = transports.KnowledgeBasesGrpcAsyncIOTransport( + unset_fields = transport.list_knowledge_bases._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_knowledge_bases_rest_interceptors(null_interceptor): + transport = transports.KnowledgeBasesRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.KnowledgeBasesRestInterceptor(), ) - channel = transport.grpc_channel - assert channel + client = KnowledgeBasesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "post_list_knowledge_bases" + ) as post, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "pre_list_knowledge_bases" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = knowledge_base.ListKnowledgeBasesRequest.pb( + knowledge_base.ListKnowledgeBasesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = knowledge_base.ListKnowledgeBasesResponse.to_json( + knowledge_base.ListKnowledgeBasesResponse() + ) + request = knowledge_base.ListKnowledgeBasesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = knowledge_base.ListKnowledgeBasesResponse() -@pytest.mark.parametrize( - "transport_class", - [ - transports.KnowledgeBasesGrpcTransport, - transports.KnowledgeBasesGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + client.list_knowledge_bases( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + pre.assert_called_once() + post.assert_called_once() -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = KnowledgeBasesClient.get_transport_class(transport_name)( + +def test_list_knowledge_bases_rest_bad_request( + transport: str = "rest", request_type=knowledge_base.ListKnowledgeBasesRequest +): + client = KnowledgeBasesClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - assert transport.kind == transport_name + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request = request_type(**request_init) -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_knowledge_bases(request) + + +def test_list_knowledge_bases_rest_flattened(): client = KnowledgeBasesClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.KnowledgeBasesGrpcTransport, + transport="rest", ) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = knowledge_base.ListKnowledgeBasesResponse() -def test_knowledge_bases_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.KnowledgeBasesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", ) + mock_args.update(sample_request) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = knowledge_base.ListKnowledgeBasesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value -def test_knowledge_bases_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2beta1.services.knowledge_bases.transports.KnowledgeBasesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.KnowledgeBasesTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_knowledge_bases(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/knowledgeBases" % client.transport._host, + args[1], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_knowledge_bases", - "get_knowledge_base", - "create_knowledge_base", - "delete_knowledge_base", - "update_knowledge_base", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + +def test_list_knowledge_bases_rest_flattened_error(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_knowledge_bases( + knowledge_base.ListKnowledgeBasesRequest(), + parent="parent_value", + ) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() +def test_list_knowledge_bases_rest_pager(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) -def test_knowledge_bases_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.dialogflow_v2beta1.services.knowledge_bases.transports.KnowledgeBasesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.KnowledgeBasesTransport( - credentials_file="credentials.json", - quota_project_id="octopus", - ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + knowledge_base.ListKnowledgeBasesResponse( + knowledge_bases=[ + knowledge_base.KnowledgeBase(), + knowledge_base.KnowledgeBase(), + knowledge_base.KnowledgeBase(), + ], + next_page_token="abc", + ), + knowledge_base.ListKnowledgeBasesResponse( + knowledge_bases=[], + next_page_token="def", + ), + knowledge_base.ListKnowledgeBasesResponse( + knowledge_bases=[ + knowledge_base.KnowledgeBase(), + ], + next_page_token="ghi", + ), + knowledge_base.ListKnowledgeBasesResponse( + knowledge_bases=[ + knowledge_base.KnowledgeBase(), + knowledge_base.KnowledgeBase(), + ], ), - quota_project_id="octopus", ) + # Two responses for two calls + response = response + response + # Wrap the values into proper Response objs + response = tuple( + knowledge_base.ListKnowledgeBasesResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values -def test_knowledge_bases_base_transport_with_adc(): - # Test the default credentials are used if credentials and credentials_file are None. - with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( - "google.cloud.dialogflow_v2beta1.services.knowledge_bases.transports.KnowledgeBasesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.KnowledgeBasesTransport() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1"} + pager = client.list_knowledge_bases(request=sample_request) -def test_knowledge_bases_auth_adc(): - # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, knowledge_base.KnowledgeBase) for i in results) + + pages = list(client.list_knowledge_bases(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + knowledge_base.GetKnowledgeBaseRequest, + dict, + ], +) +def test_get_knowledge_base_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = knowledge_base.KnowledgeBase( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_knowledge_base(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, knowledge_base.KnowledgeBase) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + + +def test_get_knowledge_base_rest_required_fields( + request_type=knowledge_base.GetKnowledgeBaseRequest, +): + transport_class = transports.KnowledgeBasesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = knowledge_base.KnowledgeBase() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_knowledge_base(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_knowledge_base_rest_unset_required_fields(): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_knowledge_base._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_knowledge_base_rest_interceptors(null_interceptor): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.KnowledgeBasesRestInterceptor(), + ) + client = KnowledgeBasesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "post_get_knowledge_base" + ) as post, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "pre_get_knowledge_base" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = knowledge_base.GetKnowledgeBaseRequest.pb( + knowledge_base.GetKnowledgeBaseRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = knowledge_base.KnowledgeBase.to_json( + knowledge_base.KnowledgeBase() + ) + + request = knowledge_base.GetKnowledgeBaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = knowledge_base.KnowledgeBase() + + client.get_knowledge_base( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_knowledge_base_rest_bad_request( + transport: str = "rest", request_type=knowledge_base.GetKnowledgeBaseRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_knowledge_base(request) + + +def test_get_knowledge_base_rest_flattened(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = knowledge_base.KnowledgeBase() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/knowledgeBases/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_knowledge_base(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/knowledgeBases/*}" % client.transport._host, + args[1], + ) + + +def test_get_knowledge_base_rest_flattened_error(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_knowledge_base( + knowledge_base.GetKnowledgeBaseRequest(), + name="name_value", + ) + + +def test_get_knowledge_base_rest_error(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_knowledge_base.CreateKnowledgeBaseRequest, + dict, + ], +) +def test_create_knowledge_base_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["knowledge_base"] = { + "name": "name_value", + "display_name": "display_name_value", + "language_code": "language_code_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_knowledge_base(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_knowledge_base.KnowledgeBase) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + + +def test_create_knowledge_base_rest_required_fields( + request_type=gcd_knowledge_base.CreateKnowledgeBaseRequest, +): + transport_class = transports.KnowledgeBasesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_knowledge_base(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_knowledge_base_rest_unset_required_fields(): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_knowledge_base._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "knowledgeBase", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_knowledge_base_rest_interceptors(null_interceptor): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.KnowledgeBasesRestInterceptor(), + ) + client = KnowledgeBasesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "post_create_knowledge_base" + ) as post, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "pre_create_knowledge_base" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_knowledge_base.CreateKnowledgeBaseRequest.pb( + gcd_knowledge_base.CreateKnowledgeBaseRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_knowledge_base.KnowledgeBase.to_json( + gcd_knowledge_base.KnowledgeBase() + ) + + request = gcd_knowledge_base.CreateKnowledgeBaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_knowledge_base.KnowledgeBase() + + client.create_knowledge_base( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_knowledge_base_rest_bad_request( + transport: str = "rest", request_type=gcd_knowledge_base.CreateKnowledgeBaseRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1"} + request_init["knowledge_base"] = { + "name": "name_value", + "display_name": "display_name_value", + "language_code": "language_code_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_knowledge_base(request) + + +def test_create_knowledge_base_rest_flattened(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + knowledge_base=gcd_knowledge_base.KnowledgeBase(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_knowledge_base(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*}/knowledgeBases" % client.transport._host, + args[1], + ) + + +def test_create_knowledge_base_rest_flattened_error(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_knowledge_base( + gcd_knowledge_base.CreateKnowledgeBaseRequest(), + parent="parent_value", + knowledge_base=gcd_knowledge_base.KnowledgeBase(name="name_value"), + ) + + +def test_create_knowledge_base_rest_error(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + knowledge_base.DeleteKnowledgeBaseRequest, + dict, + ], +) +def test_delete_knowledge_base_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_knowledge_base(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_knowledge_base_rest_required_fields( + request_type=knowledge_base.DeleteKnowledgeBaseRequest, +): + transport_class = transports.KnowledgeBasesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_knowledge_base._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("force",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_knowledge_base(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_knowledge_base_rest_unset_required_fields(): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_knowledge_base._get_unset_required_fields({}) + assert set(unset_fields) == (set(("force",)) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_knowledge_base_rest_interceptors(null_interceptor): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.KnowledgeBasesRestInterceptor(), + ) + client = KnowledgeBasesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "pre_delete_knowledge_base" + ) as pre: + pre.assert_not_called() + pb_message = knowledge_base.DeleteKnowledgeBaseRequest.pb( + knowledge_base.DeleteKnowledgeBaseRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = knowledge_base.DeleteKnowledgeBaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_knowledge_base( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_knowledge_base_rest_bad_request( + transport: str = "rest", request_type=knowledge_base.DeleteKnowledgeBaseRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/knowledgeBases/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_knowledge_base(request) + + +def test_delete_knowledge_base_rest_flattened(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/knowledgeBases/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_knowledge_base(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/knowledgeBases/*}" % client.transport._host, + args[1], + ) + + +def test_delete_knowledge_base_rest_flattened_error(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_knowledge_base( + knowledge_base.DeleteKnowledgeBaseRequest(), + name="name_value", + ) + + +def test_delete_knowledge_base_rest_error(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_knowledge_base.UpdateKnowledgeBaseRequest, + dict, + ], +) +def test_update_knowledge_base_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "knowledge_base": {"name": "projects/sample1/knowledgeBases/sample2"} + } + request_init["knowledge_base"] = { + "name": "projects/sample1/knowledgeBases/sample2", + "display_name": "display_name_value", + "language_code": "language_code_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase( + name="name_value", + display_name="display_name_value", + language_code="language_code_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_knowledge_base(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_knowledge_base.KnowledgeBase) + assert response.name == "name_value" + assert response.display_name == "display_name_value" + assert response.language_code == "language_code_value" + + +def test_update_knowledge_base_rest_required_fields( + request_type=gcd_knowledge_base.UpdateKnowledgeBaseRequest, +): + transport_class = transports.KnowledgeBasesRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_knowledge_base._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_knowledge_base._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_knowledge_base(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_knowledge_base_rest_unset_required_fields(): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_knowledge_base._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("knowledgeBase",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_knowledge_base_rest_interceptors(null_interceptor): + transport = transports.KnowledgeBasesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.KnowledgeBasesRestInterceptor(), + ) + client = KnowledgeBasesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "post_update_knowledge_base" + ) as post, mock.patch.object( + transports.KnowledgeBasesRestInterceptor, "pre_update_knowledge_base" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_knowledge_base.UpdateKnowledgeBaseRequest.pb( + gcd_knowledge_base.UpdateKnowledgeBaseRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_knowledge_base.KnowledgeBase.to_json( + gcd_knowledge_base.KnowledgeBase() + ) + + request = gcd_knowledge_base.UpdateKnowledgeBaseRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_knowledge_base.KnowledgeBase() + + client.update_knowledge_base( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_knowledge_base_rest_bad_request( + transport: str = "rest", request_type=gcd_knowledge_base.UpdateKnowledgeBaseRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "knowledge_base": {"name": "projects/sample1/knowledgeBases/sample2"} + } + request_init["knowledge_base"] = { + "name": "projects/sample1/knowledgeBases/sample2", + "display_name": "display_name_value", + "language_code": "language_code_value", + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_knowledge_base(request) + + +def test_update_knowledge_base_rest_flattened(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_knowledge_base.KnowledgeBase() + + # get arguments that satisfy an http rule for this method + sample_request = { + "knowledge_base": {"name": "projects/sample1/knowledgeBases/sample2"} + } + + # get truthy value for each flattened field + mock_args = dict( + knowledge_base=gcd_knowledge_base.KnowledgeBase(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_knowledge_base.KnowledgeBase.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_knowledge_base(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{knowledge_base.name=projects/*/knowledgeBases/*}" + % client.transport._host, + args[1], + ) + + +def test_update_knowledge_base_rest_flattened_error(transport: str = "rest"): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_knowledge_base( + gcd_knowledge_base.UpdateKnowledgeBaseRequest(), + knowledge_base=gcd_knowledge_base.KnowledgeBase(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_knowledge_base_rest_error(): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = KnowledgeBasesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = KnowledgeBasesClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = KnowledgeBasesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = KnowledgeBasesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = KnowledgeBasesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.KnowledgeBasesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.KnowledgeBasesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.KnowledgeBasesGrpcTransport, + transports.KnowledgeBasesGrpcAsyncIOTransport, + transports.KnowledgeBasesRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = KnowledgeBasesClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.KnowledgeBasesGrpcTransport, + ) + + +def test_knowledge_bases_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.KnowledgeBasesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_knowledge_bases_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2beta1.services.knowledge_bases.transports.KnowledgeBasesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.KnowledgeBasesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_knowledge_bases", + "get_knowledge_base", + "create_knowledge_base", + "delete_knowledge_base", + "update_knowledge_base", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_knowledge_bases_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.dialogflow_v2beta1.services.knowledge_bases.transports.KnowledgeBasesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.KnowledgeBasesTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_knowledge_bases_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.dialogflow_v2beta1.services.knowledge_bases.transports.KnowledgeBasesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.KnowledgeBasesTransport() + adc.assert_called_once() + + +def test_knowledge_bases_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: adc.return_value = (ga_credentials.AnonymousCredentials(), None) KnowledgeBasesClient() adc.assert_called_once_with( @@ -2391,6 +3861,7 @@ def test_knowledge_bases_transport_auth_adc(transport_class): [ transports.KnowledgeBasesGrpcTransport, transports.KnowledgeBasesGrpcAsyncIOTransport, + transports.KnowledgeBasesRestTransport, ], ) def test_knowledge_bases_transport_auth_gdch_credentials(transport_class): @@ -2491,11 +3962,23 @@ def test_knowledge_bases_grpc_transport_client_cert_source_for_mtls(transport_cl ) +def test_knowledge_bases_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.KnowledgeBasesRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_knowledge_bases_host_no_port(transport_name): @@ -2506,7 +3989,11 @@ def test_knowledge_bases_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2514,6 +4001,7 @@ def test_knowledge_bases_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_knowledge_bases_host_with_port(transport_name): @@ -2524,7 +4012,45 @@ def test_knowledge_bases_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_knowledge_bases_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = KnowledgeBasesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = KnowledgeBasesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_knowledge_bases._session + session2 = client2.transport.list_knowledge_bases._session + assert session1 != session2 + session1 = client1.transport.get_knowledge_base._session + session2 = client2.transport.get_knowledge_base._session + assert session1 != session2 + session1 = client1.transport.create_knowledge_base._session + session2 = client2.transport.create_knowledge_base._session + assert session1 != session2 + session1 = client1.transport.delete_knowledge_base._session + session2 = client2.transport.delete_knowledge_base._session + assert session1 != session2 + session1 = client1.transport.update_knowledge_base._session + session2 = client2.transport.update_knowledge_base._session + assert session1 != session2 def test_knowledge_bases_grpc_transport_channel(): @@ -2816,6 +4342,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = KnowledgeBasesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = KnowledgeBasesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3535,6 +5347,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3552,6 +5365,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_participants.py b/tests/unit/gapic/dialogflow_v2beta1/test_participants.py index 2214ea535..b0e87b41c 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_participants.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_participants.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,6 +36,7 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore from google.type import latlng_pb2 # type: ignore @@ -42,6 +45,8 @@ from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.participants import ( ParticipantsAsyncClient, @@ -106,6 +111,7 @@ def test__get_default_mtls_endpoint(): [ (ParticipantsClient, "grpc"), (ParticipantsAsyncClient, "grpc_asyncio"), + (ParticipantsClient, "rest"), ], ) def test_participants_client_from_service_account_info(client_class, transport_name): @@ -119,7 +125,11 @@ def test_participants_client_from_service_account_info(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -127,6 +137,7 @@ def test_participants_client_from_service_account_info(client_class, transport_n [ (transports.ParticipantsGrpcTransport, "grpc"), (transports.ParticipantsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.ParticipantsRestTransport, "rest"), ], ) def test_participants_client_service_account_always_use_jwt( @@ -152,6 +163,7 @@ def test_participants_client_service_account_always_use_jwt( [ (ParticipantsClient, "grpc"), (ParticipantsAsyncClient, "grpc_asyncio"), + (ParticipantsClient, "rest"), ], ) def test_participants_client_from_service_account_file(client_class, transport_name): @@ -172,13 +184,18 @@ def test_participants_client_from_service_account_file(client_class, transport_n assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_participants_client_get_transport_class(): transport = ParticipantsClient.get_transport_class() available_transports = [ transports.ParticipantsGrpcTransport, + transports.ParticipantsRestTransport, ] assert transport in available_transports @@ -195,6 +212,7 @@ def test_participants_client_get_transport_class(): transports.ParticipantsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ParticipantsClient, transports.ParticipantsRestTransport, "rest"), ], ) @mock.patch.object( @@ -338,6 +356,8 @@ def test_participants_client_client_options( "grpc_asyncio", "false", ), + (ParticipantsClient, transports.ParticipantsRestTransport, "rest", "true"), + (ParticipantsClient, transports.ParticipantsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -531,6 +551,7 @@ def test_participants_client_get_mtls_endpoint_and_cert_source(client_class): transports.ParticipantsGrpcAsyncIOTransport, "grpc_asyncio", ), + (ParticipantsClient, transports.ParticipantsRestTransport, "rest"), ], ) def test_participants_client_client_options_scopes( @@ -571,6 +592,7 @@ def test_participants_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (ParticipantsClient, transports.ParticipantsRestTransport, "rest", None), ], ) def test_participants_client_client_options_credentials_file( @@ -3473,201 +3495,2878 @@ async def test_compile_suggestion_field_headers_async(): ) in kw["metadata"] -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.ParticipantsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + gcd_participant.CreateParticipantRequest, + dict, + ], +) +def test_create_participant_rest(request_type): + client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = ParticipantsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request_init["participant"] = { + "name": "name_value", + "role": 1, + "obfuscated_external_user_id": "obfuscated_external_user_id_value", + "documents_metadata_filters": {}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant( + name="name_value", + role=gcd_participant.Participant.Role.HUMAN_AGENT, + obfuscated_external_user_id="obfuscated_external_user_id_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.ParticipantsGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = ParticipantsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_participant(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_participant.Participant) + assert response.name == "name_value" + assert response.role == gcd_participant.Participant.Role.HUMAN_AGENT + assert response.obfuscated_external_user_id == "obfuscated_external_user_id_value" + + +def test_create_participant_rest_required_fields( + request_type=gcd_participant.CreateParticipantRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, ) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.ParticipantsGrpcTransport( + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_participant._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_participant._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_participant(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_participant_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ParticipantsClient( - client_options=options, - transport=transport, - ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = ParticipantsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + unset_fields = transport.create_participant._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "participant", + ) ) + ) - # It is an error to provide scopes and a transport instance. - transport = transports.ParticipantsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_participant_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), ) - with pytest.raises(ValueError): - client = ParticipantsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_create_participant" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_create_participant" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_participant.CreateParticipantRequest.pb( + gcd_participant.CreateParticipantRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_participant.Participant.to_json( + gcd_participant.Participant() ) + request = gcd_participant.CreateParticipantRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_participant.Participant() -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.ParticipantsGrpcTransport( + client.create_participant( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_participant_rest_bad_request( + transport: str = "rest", request_type=gcd_participant.CreateParticipantRequest +): + client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - client = ParticipantsClient(transport=transport) - assert client.transport is transport + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request_init["participant"] = { + "name": "name_value", + "role": 1, + "obfuscated_external_user_id": "obfuscated_external_user_id_value", + "documents_metadata_filters": {}, + } + request = request_type(**request_init) -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.ParticipantsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_participant(request) + + +def test_create_participant_rest_flattened(): + client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel - transport = transports.ParticipantsGrpcAsyncIOTransport( + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + participant=gcd_participant.Participant(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_participant(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/conversations/*}/participants" + % client.transport._host, + args[1], + ) + + +def test_create_participant_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_participant( + gcd_participant.CreateParticipantRequest(), + parent="parent_value", + participant=gcd_participant.Participant(name="name_value"), + ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.ParticipantsGrpcTransport, - transports.ParticipantsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + +def test_create_participant_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + participant.GetParticipantRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = ParticipantsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name - - -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. +def test_get_participant_rest(request_type): client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.ParticipantsGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) -def test_participants_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.ParticipantsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.Participant( + name="name_value", + role=participant.Participant.Role.HUMAN_AGENT, + obfuscated_external_user_id="obfuscated_external_user_id_value", ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_participants_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2beta1.services.participants.transports.ParticipantsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.ParticipantsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_participant(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "create_participant", - "get_participant", - "list_participants", - "update_participant", - "analyze_content", - "streaming_analyze_content", - "suggest_articles", - "suggest_faq_answers", - "suggest_smart_replies", - "list_suggestions", - "compile_suggestion", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + # Establish that the response is the type that we expect. + assert isinstance(response, participant.Participant) + assert response.name == "name_value" + assert response.role == participant.Participant.Role.HUMAN_AGENT + assert response.obfuscated_external_user_id == "obfuscated_external_user_id_value" + + +def test_get_participant_rest_required_fields( + request_type=participant.GetParticipantRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_participant._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + # verify required fields with default values are now present -def test_participants_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.dialogflow_v2beta1.services.participants.transports.ParticipantsTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.ParticipantsTransport( - credentials_file="credentials.json", - quota_project_id="octopus", - ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", - ) + jsonified_request["name"] = "name_value" + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_participant._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) -def test_participants_base_transport_with_adc(): + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = participant.Participant() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_participant(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_participant_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_participant._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_participant_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_get_participant" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_get_participant" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.GetParticipantRequest.pb( + participant.GetParticipantRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.Participant.to_json( + participant.Participant() + ) + + request = participant.GetParticipantRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.Participant() + + client.get_participant( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_participant_rest_bad_request( + transport: str = "rest", request_type=participant.GetParticipantRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_participant(request) + + +def test_get_participant_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.Participant() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_participant(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/conversations/*/participants/*}" + % client.transport._host, + args[1], + ) + + +def test_get_participant_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_participant( + participant.GetParticipantRequest(), + name="name_value", + ) + + +def test_get_participant_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + participant.ListParticipantsRequest, + dict, + ], +) +def test_list_participants_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.ListParticipantsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.ListParticipantsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_participants(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListParticipantsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_participants_rest_required_fields( + request_type=participant.ListParticipantsRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_participants._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_participants._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = participant.ListParticipantsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = participant.ListParticipantsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_participants(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_participants_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_participants._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_participants_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_list_participants" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_list_participants" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.ListParticipantsRequest.pb( + participant.ListParticipantsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.ListParticipantsResponse.to_json( + participant.ListParticipantsResponse() + ) + + request = participant.ListParticipantsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.ListParticipantsResponse() + + client.list_participants( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_participants_rest_bad_request( + transport: str = "rest", request_type=participant.ListParticipantsRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/conversations/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_participants(request) + + +def test_list_participants_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.ListParticipantsResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/conversations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.ListParticipantsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_participants(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/conversations/*}/participants" + % client.transport._host, + args[1], + ) + + +def test_list_participants_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_participants( + participant.ListParticipantsRequest(), + parent="parent_value", + ) + + +def test_list_participants_rest_pager(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + participant.ListParticipantsResponse( + participants=[ + participant.Participant(), + participant.Participant(), + participant.Participant(), + ], + next_page_token="abc", + ), + participant.ListParticipantsResponse( + participants=[], + next_page_token="def", + ), + participant.ListParticipantsResponse( + participants=[ + participant.Participant(), + ], + next_page_token="ghi", + ), + participant.ListParticipantsResponse( + participants=[ + participant.Participant(), + participant.Participant(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + participant.ListParticipantsResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/conversations/sample2"} + + pager = client.list_participants(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, participant.Participant) for i in results) + + pages = list(client.list_participants(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_participant.UpdateParticipantRequest, + dict, + ], +) +def test_update_participant_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "participant": { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + } + request_init["participant"] = { + "name": "projects/sample1/conversations/sample2/participants/sample3", + "role": 1, + "obfuscated_external_user_id": "obfuscated_external_user_id_value", + "documents_metadata_filters": {}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant( + name="name_value", + role=gcd_participant.Participant.Role.HUMAN_AGENT, + obfuscated_external_user_id="obfuscated_external_user_id_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_participant(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_participant.Participant) + assert response.name == "name_value" + assert response.role == gcd_participant.Participant.Role.HUMAN_AGENT + assert response.obfuscated_external_user_id == "obfuscated_external_user_id_value" + + +def test_update_participant_rest_required_fields( + request_type=gcd_participant.UpdateParticipantRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_participant._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_participant._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_participant(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_participant_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_participant._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "participant", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_participant_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_update_participant" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_update_participant" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_participant.UpdateParticipantRequest.pb( + gcd_participant.UpdateParticipantRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_participant.Participant.to_json( + gcd_participant.Participant() + ) + + request = gcd_participant.UpdateParticipantRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_participant.Participant() + + client.update_participant( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_participant_rest_bad_request( + transport: str = "rest", request_type=gcd_participant.UpdateParticipantRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "participant": { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + } + request_init["participant"] = { + "name": "projects/sample1/conversations/sample2/participants/sample3", + "role": 1, + "obfuscated_external_user_id": "obfuscated_external_user_id_value", + "documents_metadata_filters": {}, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_participant(request) + + +def test_update_participant_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.Participant() + + # get arguments that satisfy an http rule for this method + sample_request = { + "participant": { + "name": "projects/sample1/conversations/sample2/participants/sample3" + } + } + + # get truthy value for each flattened field + mock_args = dict( + participant=gcd_participant.Participant(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.Participant.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_participant(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{participant.name=projects/*/conversations/*/participants/*}" + % client.transport._host, + args[1], + ) + + +def test_update_participant_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_participant( + gcd_participant.UpdateParticipantRequest(), + participant=gcd_participant.Participant(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_participant_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_participant.AnalyzeContentRequest, + dict, + ], +) +def test_analyze_content_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "participant": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.AnalyzeContentResponse( + reply_text="reply_text_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.AnalyzeContentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.analyze_content(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_participant.AnalyzeContentResponse) + assert response.reply_text == "reply_text_value" + + +def test_analyze_content_rest_required_fields( + request_type=gcd_participant.AnalyzeContentRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["participant"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_content._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["participant"] = "participant_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).analyze_content._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "participant" in jsonified_request + assert jsonified_request["participant"] == "participant_value" + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_participant.AnalyzeContentResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_participant.AnalyzeContentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.analyze_content(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_analyze_content_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.analyze_content._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("participant",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_analyze_content_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_analyze_content" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_analyze_content" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_participant.AnalyzeContentRequest.pb( + gcd_participant.AnalyzeContentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_participant.AnalyzeContentResponse.to_json( + gcd_participant.AnalyzeContentResponse() + ) + + request = gcd_participant.AnalyzeContentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_participant.AnalyzeContentResponse() + + client.analyze_content( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_analyze_content_rest_bad_request( + transport: str = "rest", request_type=gcd_participant.AnalyzeContentRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "participant": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.analyze_content(request) + + +def test_analyze_content_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_participant.AnalyzeContentResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "participant": "projects/sample1/conversations/sample2/participants/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + participant="participant_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_participant.AnalyzeContentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.analyze_content(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{participant=projects/*/conversations/*/participants/*}:analyzeContent" + % client.transport._host, + args[1], + ) + + +def test_analyze_content_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.analyze_content( + gcd_participant.AnalyzeContentRequest(), + participant="participant_value", + text_input=session.TextInput(text="text_value"), + audio_input=gcd_participant.AudioInput( + config=audio_config.InputAudioConfig( + audio_encoding=audio_config.AudioEncoding.AUDIO_ENCODING_LINEAR_16 + ) + ), + event_input=session.EventInput(name="name_value"), + ) + + +def test_analyze_content_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_streaming_analyze_content_rest_no_http_options(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = participant.StreamingAnalyzeContentRequest() + requests = [request] + with pytest.raises(RuntimeError): + client.streaming_analyze_content(requests) + + +@pytest.mark.parametrize( + "request_type", + [ + participant.SuggestArticlesRequest, + dict, + ], +) +def test_suggest_articles_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestArticlesResponse( + latest_message="latest_message_value", + context_size=1311, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestArticlesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.suggest_articles(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, participant.SuggestArticlesResponse) + assert response.latest_message == "latest_message_value" + assert response.context_size == 1311 + + +def test_suggest_articles_rest_required_fields( + request_type=participant.SuggestArticlesRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_articles._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_articles._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = participant.SuggestArticlesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = participant.SuggestArticlesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.suggest_articles(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_suggest_articles_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.suggest_articles._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_suggest_articles_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_suggest_articles" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_suggest_articles" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.SuggestArticlesRequest.pb( + participant.SuggestArticlesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.SuggestArticlesResponse.to_json( + participant.SuggestArticlesResponse() + ) + + request = participant.SuggestArticlesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.SuggestArticlesResponse() + + client.suggest_articles( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_suggest_articles_rest_bad_request( + transport: str = "rest", request_type=participant.SuggestArticlesRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.suggest_articles(request) + + +def test_suggest_articles_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestArticlesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestArticlesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.suggest_articles(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestArticles" + % client.transport._host, + args[1], + ) + + +def test_suggest_articles_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.suggest_articles( + participant.SuggestArticlesRequest(), + parent="parent_value", + ) + + +def test_suggest_articles_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + participant.SuggestFaqAnswersRequest, + dict, + ], +) +def test_suggest_faq_answers_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestFaqAnswersResponse( + latest_message="latest_message_value", + context_size=1311, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestFaqAnswersResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.suggest_faq_answers(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, participant.SuggestFaqAnswersResponse) + assert response.latest_message == "latest_message_value" + assert response.context_size == 1311 + + +def test_suggest_faq_answers_rest_required_fields( + request_type=participant.SuggestFaqAnswersRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_faq_answers._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_faq_answers._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = participant.SuggestFaqAnswersResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = participant.SuggestFaqAnswersResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.suggest_faq_answers(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_suggest_faq_answers_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.suggest_faq_answers._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_suggest_faq_answers_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_suggest_faq_answers" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_suggest_faq_answers" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.SuggestFaqAnswersRequest.pb( + participant.SuggestFaqAnswersRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.SuggestFaqAnswersResponse.to_json( + participant.SuggestFaqAnswersResponse() + ) + + request = participant.SuggestFaqAnswersRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.SuggestFaqAnswersResponse() + + client.suggest_faq_answers( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_suggest_faq_answers_rest_bad_request( + transport: str = "rest", request_type=participant.SuggestFaqAnswersRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.suggest_faq_answers(request) + + +def test_suggest_faq_answers_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestFaqAnswersResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestFaqAnswersResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.suggest_faq_answers(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestFaqAnswers" + % client.transport._host, + args[1], + ) + + +def test_suggest_faq_answers_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.suggest_faq_answers( + participant.SuggestFaqAnswersRequest(), + parent="parent_value", + ) + + +def test_suggest_faq_answers_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + participant.SuggestSmartRepliesRequest, + dict, + ], +) +def test_suggest_smart_replies_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestSmartRepliesResponse( + latest_message="latest_message_value", + context_size=1311, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestSmartRepliesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.suggest_smart_replies(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, participant.SuggestSmartRepliesResponse) + assert response.latest_message == "latest_message_value" + assert response.context_size == 1311 + + +def test_suggest_smart_replies_rest_required_fields( + request_type=participant.SuggestSmartRepliesRequest, +): + transport_class = transports.ParticipantsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_smart_replies._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).suggest_smart_replies._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = participant.SuggestSmartRepliesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = participant.SuggestSmartRepliesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.suggest_smart_replies(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_suggest_smart_replies_rest_unset_required_fields(): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.suggest_smart_replies._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("parent",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_suggest_smart_replies_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_suggest_smart_replies" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_suggest_smart_replies" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.SuggestSmartRepliesRequest.pb( + participant.SuggestSmartRepliesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.SuggestSmartRepliesResponse.to_json( + participant.SuggestSmartRepliesResponse() + ) + + request = participant.SuggestSmartRepliesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.SuggestSmartRepliesResponse() + + client.suggest_smart_replies( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_suggest_smart_replies_rest_bad_request( + transport: str = "rest", request_type=participant.SuggestSmartRepliesRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.suggest_smart_replies(request) + + +def test_suggest_smart_replies_rest_flattened(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.SuggestSmartRepliesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.SuggestSmartRepliesResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.suggest_smart_replies(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/conversations/*/participants/*}/suggestions:suggestSmartReplies" + % client.transport._host, + args[1], + ) + + +def test_suggest_smart_replies_rest_flattened_error(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.suggest_smart_replies( + participant.SuggestSmartRepliesRequest(), + parent="parent_value", + ) + + +def test_suggest_smart_replies_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + participant.ListSuggestionsRequest, + dict, + ], +) +def test_list_suggestions_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.ListSuggestionsResponse( + next_page_token="next_page_token_value", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.ListSuggestionsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_suggestions(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListSuggestionsPager) + assert response.next_page_token == "next_page_token_value" + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_suggestions_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_list_suggestions" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_list_suggestions" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.ListSuggestionsRequest.pb( + participant.ListSuggestionsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.ListSuggestionsResponse.to_json( + participant.ListSuggestionsResponse() + ) + + request = participant.ListSuggestionsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.ListSuggestionsResponse() + + client.list_suggestions( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_list_suggestions_rest_bad_request( + transport: str = "rest", request_type=participant.ListSuggestionsRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_suggestions(request) + + +def test_list_suggestions_rest_pager(transport: str = "rest"): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + participant.ListSuggestionsResponse( + suggestions=[ + participant.Suggestion(), + participant.Suggestion(), + participant.Suggestion(), + ], + next_page_token="abc", + ), + participant.ListSuggestionsResponse( + suggestions=[], + next_page_token="def", + ), + participant.ListSuggestionsResponse( + suggestions=[ + participant.Suggestion(), + ], + next_page_token="ghi", + ), + participant.ListSuggestionsResponse( + suggestions=[ + participant.Suggestion(), + participant.Suggestion(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + participant.ListSuggestionsResponse.to_json(x) for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + + pager = client.list_suggestions(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, participant.Suggestion) for i in results) + + pages = list(client.list_suggestions(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + participant.CompileSuggestionRequest, + dict, + ], +) +def test_compile_suggestion_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = participant.CompileSuggestionResponse( + latest_message="latest_message_value", + context_size=1311, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = participant.CompileSuggestionResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.compile_suggestion(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, participant.CompileSuggestionResponse) + assert response.latest_message == "latest_message_value" + assert response.context_size == 1311 + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_compile_suggestion_rest_interceptors(null_interceptor): + transport = transports.ParticipantsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.ParticipantsRestInterceptor(), + ) + client = ParticipantsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.ParticipantsRestInterceptor, "post_compile_suggestion" + ) as post, mock.patch.object( + transports.ParticipantsRestInterceptor, "pre_compile_suggestion" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = participant.CompileSuggestionRequest.pb( + participant.CompileSuggestionRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = participant.CompileSuggestionResponse.to_json( + participant.CompileSuggestionResponse() + ) + + request = participant.CompileSuggestionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = participant.CompileSuggestionResponse() + + client.compile_suggestion( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_compile_suggestion_rest_bad_request( + transport: str = "rest", request_type=participant.CompileSuggestionRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/conversations/sample2/participants/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.compile_suggestion(request) + + +def test_compile_suggestion_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_streaming_analyze_content_rest_error(): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + # Since a `google.api.http` annotation is required for using a rest transport + # method, this should error. + with pytest.raises(NotImplementedError) as not_implemented_error: + client.streaming_analyze_content({}) + assert "Method StreamingAnalyzeContent is not available over REST transport" in str( + not_implemented_error.value + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ParticipantsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ParticipantsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = ParticipantsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = ParticipantsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = ParticipantsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.ParticipantsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.ParticipantsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ParticipantsGrpcTransport, + transports.ParticipantsGrpcAsyncIOTransport, + transports.ParticipantsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = ParticipantsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.ParticipantsGrpcTransport, + ) + + +def test_participants_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.ParticipantsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_participants_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2beta1.services.participants.transports.ParticipantsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.ParticipantsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "create_participant", + "get_participant", + "list_participants", + "update_participant", + "analyze_content", + "streaming_analyze_content", + "suggest_articles", + "suggest_faq_answers", + "suggest_smart_replies", + "list_suggestions", + "compile_suggestion", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_participants_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.dialogflow_v2beta1.services.participants.transports.ParticipantsTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.ParticipantsTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_participants_base_transport_with_adc(): # Test the default credentials are used if credentials and credentials_file are None. with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( "google.cloud.dialogflow_v2beta1.services.participants.transports.ParticipantsTransport._prep_wrapped_messages" @@ -3721,6 +6420,7 @@ def test_participants_transport_auth_adc(transport_class): [ transports.ParticipantsGrpcTransport, transports.ParticipantsGrpcAsyncIOTransport, + transports.ParticipantsRestTransport, ], ) def test_participants_transport_auth_gdch_credentials(transport_class): @@ -3818,11 +6518,23 @@ def test_participants_grpc_transport_client_cert_source_for_mtls(transport_class ) +def test_participants_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.ParticipantsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_participants_host_no_port(transport_name): @@ -3833,7 +6545,11 @@ def test_participants_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -3841,6 +6557,7 @@ def test_participants_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_participants_host_with_port(transport_name): @@ -3851,7 +6568,63 @@ def test_participants_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_participants_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = ParticipantsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = ParticipantsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.create_participant._session + session2 = client2.transport.create_participant._session + assert session1 != session2 + session1 = client1.transport.get_participant._session + session2 = client2.transport.get_participant._session + assert session1 != session2 + session1 = client1.transport.list_participants._session + session2 = client2.transport.list_participants._session + assert session1 != session2 + session1 = client1.transport.update_participant._session + session2 = client2.transport.update_participant._session + assert session1 != session2 + session1 = client1.transport.analyze_content._session + session2 = client2.transport.analyze_content._session + assert session1 != session2 + session1 = client1.transport.streaming_analyze_content._session + session2 = client2.transport.streaming_analyze_content._session + assert session1 != session2 + session1 = client1.transport.suggest_articles._session + session2 = client2.transport.suggest_articles._session + assert session1 != session2 + session1 = client1.transport.suggest_faq_answers._session + session2 = client2.transport.suggest_faq_answers._session + assert session1 != session2 + session1 = client1.transport.suggest_smart_replies._session + session2 = client2.transport.suggest_smart_replies._session + assert session1 != session2 + session1 = client1.transport.list_suggestions._session + session2 = client2.transport.list_suggestions._session + assert session1 != session2 + session1 = client1.transport.compile_suggestion._session + session2 = client2.transport.compile_suggestion._session + assert session1 != session2 def test_participants_grpc_transport_channel(): @@ -4292,6 +7065,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = ParticipantsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = ParticipantsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -5009,6 +8068,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -5026,6 +8086,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_session_entity_types.py b/tests/unit/gapic/dialogflow_v2beta1/test_session_entity_types.py index 995d7cbcd..32b9f8fab 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_session_entity_types.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_session_entity_types.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,11 +36,14 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.session_entity_types import ( SessionEntityTypesAsyncClient, @@ -103,6 +108,7 @@ def test__get_default_mtls_endpoint(): [ (SessionEntityTypesClient, "grpc"), (SessionEntityTypesAsyncClient, "grpc_asyncio"), + (SessionEntityTypesClient, "rest"), ], ) def test_session_entity_types_client_from_service_account_info( @@ -118,7 +124,11 @@ def test_session_entity_types_client_from_service_account_info( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -126,6 +136,7 @@ def test_session_entity_types_client_from_service_account_info( [ (transports.SessionEntityTypesGrpcTransport, "grpc"), (transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.SessionEntityTypesRestTransport, "rest"), ], ) def test_session_entity_types_client_service_account_always_use_jwt( @@ -151,6 +162,7 @@ def test_session_entity_types_client_service_account_always_use_jwt( [ (SessionEntityTypesClient, "grpc"), (SessionEntityTypesAsyncClient, "grpc_asyncio"), + (SessionEntityTypesClient, "rest"), ], ) def test_session_entity_types_client_from_service_account_file( @@ -173,13 +185,18 @@ def test_session_entity_types_client_from_service_account_file( assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_session_entity_types_client_get_transport_class(): transport = SessionEntityTypesClient.get_transport_class() available_transports = [ transports.SessionEntityTypesGrpcTransport, + transports.SessionEntityTypesRestTransport, ] assert transport in available_transports @@ -196,6 +213,7 @@ def test_session_entity_types_client_get_transport_class(): transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (SessionEntityTypesClient, transports.SessionEntityTypesRestTransport, "rest"), ], ) @mock.patch.object( @@ -351,6 +369,18 @@ def test_session_entity_types_client_client_options( "grpc_asyncio", "false", ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + "true", + ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + "false", + ), ], ) @mock.patch.object( @@ -550,6 +580,7 @@ def test_session_entity_types_client_get_mtls_endpoint_and_cert_source(client_cl transports.SessionEntityTypesGrpcAsyncIOTransport, "grpc_asyncio", ), + (SessionEntityTypesClient, transports.SessionEntityTypesRestTransport, "rest"), ], ) def test_session_entity_types_client_client_options_scopes( @@ -590,6 +621,12 @@ def test_session_entity_types_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + ( + SessionEntityTypesClient, + transports.SessionEntityTypesRestTransport, + "rest", + None, + ), ], ) def test_session_entity_types_client_client_options_credentials_file( @@ -2194,224 +2231,1725 @@ async def test_delete_session_entity_type_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + session_entity_type.ListSessionEntityTypesRequest, + dict, + ], +) +def test_list_session_entity_types_rest(request_type): + client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) - # It is an error to provide an api_key and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options=options, - transport=transport, + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = session_entity_type.ListSessionEntityTypesResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.pb( + return_value ) + json_return_value = json_format.MessageToJson(pb_return_value) - # It is an error to provide scopes and a transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) - with pytest.raises(ValueError): - client = SessionEntityTypesClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_session_entity_types(request) + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListSessionEntityTypesPager) + assert response.next_page_token == "next_page_token_value" -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + +def test_list_session_entity_types_rest_required_fields( + request_type=session_entity_type.ListSessionEntityTypesRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - client = SessionEntityTypesClient(transport=transport) - assert client.transport is transport + # verify fields with default values are dropped -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.SessionEntityTypesGrpcTransport( - credentials=ga_credentials.AnonymousCredentials(), + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_session_entity_types._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_session_entity_types._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) ) - channel = transport.grpc_channel - assert channel + jsonified_request.update(unset_fields) - transport = transports.SessionEntityTypesGrpcAsyncIOTransport( + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - channel = transport.grpc_channel - assert channel + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session_entity_type.ListSessionEntityTypesResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + response_value = Response() + response_value.status_code = 200 -@pytest.mark.parametrize( - "transport_class", - [ - transports.SessionEntityTypesGrpcTransport, - transports.SessionEntityTypesGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.pb( + return_value + ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value -@pytest.mark.parametrize( - "transport_name", - [ - "grpc", - ], -) -def test_transport_kind(transport_name): - transport = SessionEntityTypesClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name + response = client.list_session_entity_types(request) + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. - client = SessionEntityTypesClient( - credentials=ga_credentials.AnonymousCredentials(), + +def test_list_session_entity_types_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials ) - assert isinstance( - client.transport, - transports.SessionEntityTypesGrpcTransport, + + unset_fields = transport.list_session_entity_types._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) ) -def test_session_entity_types_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.SessionEntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_session_entity_types_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "post_list_session_entity_types" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_list_session_entity_types" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session_entity_type.ListSessionEntityTypesRequest.pb( + session_entity_type.ListSessionEntityTypesRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = ( + session_entity_type.ListSessionEntityTypesResponse.to_json( + session_entity_type.ListSessionEntityTypesResponse() + ) ) + request = session_entity_type.ListSessionEntityTypesRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session_entity_type.ListSessionEntityTypesResponse() -def test_session_entity_types_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2beta1.services.session_entity_types.transports.SessionEntityTypesTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.SessionEntityTypesTransport( - credentials=ga_credentials.AnonymousCredentials(), + client.list_session_entity_types( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_session_entity_types", - "get_session_entity_type", - "create_session_entity_type", - "update_session_entity_type", - "delete_session_entity_type", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + pre.assert_called_once() + post.assert_called_once() + + +def test_list_session_entity_types_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.ListSessionEntityTypesRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_session_entity_types(request) -def test_session_entity_types_base_transport_with_credentials_file(): - # Instantiate the base transport with a credentials file - with mock.patch.object( - google.auth, "load_credentials_from_file", autospec=True - ) as load_creds, mock.patch( - "google.cloud.dialogflow_v2beta1.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.SessionEntityTypesTransport( - credentials_file="credentials.json", - quota_project_id="octopus", +def test_list_session_entity_types_rest_flattened(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = session_entity_type.ListSessionEntityTypesResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", ) - load_creds.assert_called_once_with( - "credentials.json", - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id="octopus", + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.ListSessionEntityTypesResponse.pb( + return_value ) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + client.list_session_entity_types(**mock_args) -def test_session_entity_types_base_transport_with_adc(): - # Test the default credentials are used if credentials and credentials_file are None. - with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( - "google.cloud.dialogflow_v2beta1.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" - ) as Transport: - Transport.return_value = None - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport = transports.SessionEntityTypesTransport() - adc.assert_called_once() + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent/sessions/*}/entityTypes" + % client.transport._host, + args[1], + ) -def test_session_entity_types_auth_adc(): - # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(google.auth, "default", autospec=True) as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - SessionEntityTypesClient() - adc.assert_called_once_with( - scopes=None, - default_scopes=( - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/dialogflow", - ), - quota_project_id=None, +def test_list_session_entity_types_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_session_entity_types( + session_entity_type.ListSessionEntityTypesRequest(), + parent="parent_value", ) -@pytest.mark.parametrize( - "transport_class", - [ - transports.SessionEntityTypesGrpcTransport, +def test_list_session_entity_types_rest_pager(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + ], + next_page_token="abc", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[], + next_page_token="def", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + ], + next_page_token="ghi", + ), + session_entity_type.ListSessionEntityTypesResponse( + session_entity_types=[ + session_entity_type.SessionEntityType(), + session_entity_type.SessionEntityType(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + session_entity_type.ListSessionEntityTypesResponse.to_json(x) + for x in response + ) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values + + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + pager = client.list_session_entity_types(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all( + isinstance(i, session_entity_type.SessionEntityType) for i in results + ) + + pages = list(client.list_session_entity_types(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.parametrize( + "request_type", + [ + session_entity_type.GetSessionEntityTypeRequest, + dict, + ], +) +def test_get_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_get_session_entity_type_rest_required_fields( + request_type=session_entity_type.GetSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = session_entity_type.SessionEntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "post_get_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_get_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = session_entity_type.GetSessionEntityTypeRequest.pb( + session_entity_type.GetSessionEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = session_entity_type.SessionEntityType.to_json( + session_entity_type.SessionEntityType() + ) + + request = session_entity_type.GetSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = session_entity_type.SessionEntityType() + + client.get_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.GetSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_session_entity_type(request) + + +def test_get_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_session_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/agent/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_get_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_session_entity_type( + session_entity_type.GetSessionEntityTypeRequest(), + name="name_value", + ) + + +def test_get_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_session_entity_type.CreateSessionEntityTypeRequest, + dict, + ], +) +def test_create_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request_init["session_entity_type"] = { + "name": "name_value", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=gcd_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == gcd_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_create_session_entity_type_rest_required_fields( + request_type=gcd_session_entity_type.CreateSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "sessionEntityType", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "post_create_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_create_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_session_entity_type.CreateSessionEntityTypeRequest.pb( + gcd_session_entity_type.CreateSessionEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_session_entity_type.SessionEntityType.to_json( + gcd_session_entity_type.SessionEntityType() + ) + + request = gcd_session_entity_type.CreateSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_session_entity_type.SessionEntityType() + + client.create_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=gcd_session_entity_type.CreateSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent/sessions/sample2"} + request_init["session_entity_type"] = { + "name": "name_value", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_session_entity_type(request) + + +def test_create_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + session_entity_type=gcd_session_entity_type.SessionEntityType( + name="name_value" + ), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_session_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent/sessions/*}/entityTypes" + % client.transport._host, + args[1], + ) + + +def test_create_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_session_entity_type( + gcd_session_entity_type.CreateSessionEntityTypeRequest(), + parent="parent_value", + session_entity_type=gcd_session_entity_type.SessionEntityType( + name="name_value" + ), + ) + + +def test_create_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_session_entity_type.UpdateSessionEntityTypeRequest, + dict, + ], +) +def test_update_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "session_entity_type": { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + } + request_init["session_entity_type"] = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType( + name="name_value", + entity_override_mode=gcd_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_session_entity_type.SessionEntityType) + assert response.name == "name_value" + assert ( + response.entity_override_mode + == gcd_session_entity_type.SessionEntityType.EntityOverrideMode.ENTITY_OVERRIDE_MODE_OVERRIDE + ) + + +def test_update_session_entity_type_rest_required_fields( + request_type=gcd_session_entity_type.UpdateSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_session_entity_type._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("sessionEntityType",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "post_update_session_entity_type" + ) as post, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_update_session_entity_type" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_session_entity_type.UpdateSessionEntityTypeRequest.pb( + gcd_session_entity_type.UpdateSessionEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_session_entity_type.SessionEntityType.to_json( + gcd_session_entity_type.SessionEntityType() + ) + + request = gcd_session_entity_type.UpdateSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_session_entity_type.SessionEntityType() + + client.update_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=gcd_session_entity_type.UpdateSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "session_entity_type": { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + } + request_init["session_entity_type"] = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3", + "entity_override_mode": 1, + "entities": [ + {"value": "value_value", "synonyms": ["synonyms_value1", "synonyms_value2"]} + ], + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_session_entity_type(request) + + +def test_update_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session_entity_type.SessionEntityType() + + # get arguments that satisfy an http rule for this method + sample_request = { + "session_entity_type": { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + } + + # get truthy value for each flattened field + mock_args = dict( + session_entity_type=gcd_session_entity_type.SessionEntityType( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session_entity_type.SessionEntityType.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_session_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{session_entity_type.name=projects/*/agent/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_update_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_session_entity_type( + gcd_session_entity_type.UpdateSessionEntityTypeRequest(), + session_entity_type=gcd_session_entity_type.SessionEntityType( + name="name_value" + ), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + session_entity_type.DeleteSessionEntityTypeRequest, + dict, + ], +) +def test_delete_session_entity_type_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_session_entity_type(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_session_entity_type_rest_required_fields( + request_type=session_entity_type.DeleteSessionEntityTypeRequest, +): + transport_class = transports.SessionEntityTypesRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_session_entity_type._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_session_entity_type(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_session_entity_type_rest_unset_required_fields(): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_session_entity_type._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_session_entity_type_rest_interceptors(null_interceptor): + transport = transports.SessionEntityTypesRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.SessionEntityTypesRestInterceptor(), + ) + client = SessionEntityTypesClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionEntityTypesRestInterceptor, "pre_delete_session_entity_type" + ) as pre: + pre.assert_not_called() + pb_message = session_entity_type.DeleteSessionEntityTypeRequest.pb( + session_entity_type.DeleteSessionEntityTypeRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = session_entity_type.DeleteSessionEntityTypeRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_session_entity_type( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_session_entity_type_rest_bad_request( + transport: str = "rest", + request_type=session_entity_type.DeleteSessionEntityTypeRequest, +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_session_entity_type(request) + + +def test_delete_session_entity_type_rest_flattened(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/agent/sessions/sample2/entityTypes/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_session_entity_type(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/agent/sessions/*/entityTypes/*}" + % client.transport._host, + args[1], + ) + + +def test_delete_session_entity_type_rest_flattened_error(transport: str = "rest"): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_session_entity_type( + session_entity_type.DeleteSessionEntityTypeRequest(), + name="name_value", + ) + + +def test_delete_session_entity_type_rest_error(): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = SessionEntityTypesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = SessionEntityTypesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.SessionEntityTypesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.SessionEntityTypesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.SessionEntityTypesGrpcTransport, + transports.SessionEntityTypesGrpcAsyncIOTransport, + transports.SessionEntityTypesRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = SessionEntityTypesClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.SessionEntityTypesGrpcTransport, + ) + + +def test_session_entity_types_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.SessionEntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_session_entity_types_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2beta1.services.session_entity_types.transports.SessionEntityTypesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.SessionEntityTypesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_session_entity_types", + "get_session_entity_type", + "create_session_entity_type", + "update_session_entity_type", + "delete_session_entity_type", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_session_entity_types_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.dialogflow_v2beta1.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.SessionEntityTypesTransport( + credentials_file="credentials.json", + quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_session_entity_types_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( + "google.cloud.dialogflow_v2beta1.services.session_entity_types.transports.SessionEntityTypesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.SessionEntityTypesTransport() + adc.assert_called_once() + + +def test_session_entity_types_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + SessionEntityTypesClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id=None, + ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.SessionEntityTypesGrpcTransport, transports.SessionEntityTypesGrpcAsyncIOTransport, ], ) @@ -2436,6 +3974,7 @@ def test_session_entity_types_transport_auth_adc(transport_class): [ transports.SessionEntityTypesGrpcTransport, transports.SessionEntityTypesGrpcAsyncIOTransport, + transports.SessionEntityTypesRestTransport, ], ) def test_session_entity_types_transport_auth_gdch_credentials(transport_class): @@ -2538,11 +4077,23 @@ def test_session_entity_types_grpc_transport_client_cert_source_for_mtls( ) +def test_session_entity_types_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.SessionEntityTypesRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_session_entity_types_host_no_port(transport_name): @@ -2553,7 +4104,11 @@ def test_session_entity_types_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2561,6 +4116,7 @@ def test_session_entity_types_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_session_entity_types_host_with_port(transport_name): @@ -2571,7 +4127,45 @@ def test_session_entity_types_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_session_entity_types_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = SessionEntityTypesClient( + credentials=creds1, + transport=transport_name, + ) + client2 = SessionEntityTypesClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_session_entity_types._session + session2 = client2.transport.list_session_entity_types._session + assert session1 != session2 + session1 = client1.transport.get_session_entity_type._session + session2 = client2.transport.get_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.create_session_entity_type._session + session2 = client2.transport.create_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.update_session_entity_type._session + session2 = client2.transport.update_session_entity_type._session + assert session1 != session2 + session1 = client1.transport.delete_session_entity_type._session + session2 = client2.transport.delete_session_entity_type._session + assert session1 != session2 def test_session_entity_types_grpc_transport_channel(): @@ -2870,6 +4464,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = SessionEntityTypesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = SessionEntityTypesClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3589,6 +5469,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3606,6 +5487,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_sessions.py b/tests/unit/gapic/dialogflow_v2beta1/test_sessions.py index 49ede22f5..9dc0634a0 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_sessions.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_sessions.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,6 +36,7 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import struct_pb2 # type: ignore from google.rpc import status_pb2 # type: ignore from google.type import latlng_pb2 # type: ignore @@ -42,6 +45,8 @@ from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.sessions import ( SessionsAsyncClient, @@ -103,6 +108,7 @@ def test__get_default_mtls_endpoint(): [ (SessionsClient, "grpc"), (SessionsAsyncClient, "grpc_asyncio"), + (SessionsClient, "rest"), ], ) def test_sessions_client_from_service_account_info(client_class, transport_name): @@ -116,7 +122,11 @@ def test_sessions_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -124,6 +134,7 @@ def test_sessions_client_from_service_account_info(client_class, transport_name) [ (transports.SessionsGrpcTransport, "grpc"), (transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.SessionsRestTransport, "rest"), ], ) def test_sessions_client_service_account_always_use_jwt( @@ -149,6 +160,7 @@ def test_sessions_client_service_account_always_use_jwt( [ (SessionsClient, "grpc"), (SessionsAsyncClient, "grpc_asyncio"), + (SessionsClient, "rest"), ], ) def test_sessions_client_from_service_account_file(client_class, transport_name): @@ -169,13 +181,18 @@ def test_sessions_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_sessions_client_get_transport_class(): transport = SessionsClient.get_transport_class() available_transports = [ transports.SessionsGrpcTransport, + transports.SessionsRestTransport, ] assert transport in available_transports @@ -188,6 +205,7 @@ def test_sessions_client_get_transport_class(): [ (SessionsClient, transports.SessionsGrpcTransport, "grpc"), (SessionsAsyncClient, transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (SessionsClient, transports.SessionsRestTransport, "rest"), ], ) @mock.patch.object( @@ -329,6 +347,8 @@ def test_sessions_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (SessionsClient, transports.SessionsRestTransport, "rest", "true"), + (SessionsClient, transports.SessionsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -518,6 +538,7 @@ def test_sessions_client_get_mtls_endpoint_and_cert_source(client_class): [ (SessionsClient, transports.SessionsGrpcTransport, "grpc"), (SessionsAsyncClient, transports.SessionsGrpcAsyncIOTransport, "grpc_asyncio"), + (SessionsClient, transports.SessionsRestTransport, "rest"), ], ) def test_sessions_client_client_options_scopes( @@ -553,6 +574,7 @@ def test_sessions_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (SessionsClient, transports.SessionsRestTransport, "rest", None), ], ) def test_sessions_client_client_options_credentials_file( @@ -1007,6 +1029,317 @@ async def test_streaming_detect_intent_async_from_dict(): await test_streaming_detect_intent_async(request_type=dict) +@pytest.mark.parametrize( + "request_type", + [ + gcd_session.DetectIntentRequest, + dict, + ], +) +def test_detect_intent_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"session": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session.DetectIntentResponse( + response_id="response_id_value", + output_audio=b"output_audio_blob", + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session.DetectIntentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.detect_intent(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_session.DetectIntentResponse) + assert response.response_id == "response_id_value" + assert response.output_audio == b"output_audio_blob" + + +def test_detect_intent_rest_required_fields( + request_type=gcd_session.DetectIntentRequest, +): + transport_class = transports.SessionsRestTransport + + request_init = {} + request_init["session"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).detect_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["session"] = "session_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).detect_intent._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "session" in jsonified_request + assert jsonified_request["session"] == "session_value" + + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_session.DetectIntentResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_session.DetectIntentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.detect_intent(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_detect_intent_rest_unset_required_fields(): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.detect_intent._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "session", + "queryInput", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_detect_intent_rest_interceptors(null_interceptor): + transport = transports.SessionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.SessionsRestInterceptor(), + ) + client = SessionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.SessionsRestInterceptor, "post_detect_intent" + ) as post, mock.patch.object( + transports.SessionsRestInterceptor, "pre_detect_intent" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_session.DetectIntentRequest.pb( + gcd_session.DetectIntentRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_session.DetectIntentResponse.to_json( + gcd_session.DetectIntentResponse() + ) + + request = gcd_session.DetectIntentRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_session.DetectIntentResponse() + + client.detect_intent( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_detect_intent_rest_bad_request( + transport: str = "rest", request_type=gcd_session.DetectIntentRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"session": "projects/sample1/agent/sessions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.detect_intent(request) + + +def test_detect_intent_rest_flattened(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_session.DetectIntentResponse() + + # get arguments that satisfy an http rule for this method + sample_request = {"session": "projects/sample1/agent/sessions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + session="session_value", + query_input=gcd_session.QueryInput( + audio_config=audio_config.InputAudioConfig( + audio_encoding=audio_config.AudioEncoding.AUDIO_ENCODING_LINEAR_16 + ) + ), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_session.DetectIntentResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.detect_intent(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{session=projects/*/agent/sessions/*}:detectIntent" + % client.transport._host, + args[1], + ) + + +def test_detect_intent_rest_flattened_error(transport: str = "rest"): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.detect_intent( + gcd_session.DetectIntentRequest(), + session="session_value", + query_input=gcd_session.QueryInput( + audio_config=audio_config.InputAudioConfig( + audio_encoding=audio_config.AudioEncoding.AUDIO_ENCODING_LINEAR_16 + ) + ), + ) + + +def test_detect_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_streaming_detect_intent_rest_no_http_options(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = session.StreamingDetectIntentRequest() + requests = [request] + with pytest.raises(RuntimeError): + client.streaming_detect_intent(requests) + + +def test_streaming_detect_intent_rest_error(): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + # Since a `google.api.http` annotation is required for using a rest transport + # method, this should error. + with pytest.raises(NotImplementedError) as not_implemented_error: + client.streaming_detect_intent({}) + assert "Method StreamingDetectIntent is not available over REST transport" in str( + not_implemented_error.value + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.SessionsGrpcTransport( @@ -1088,6 +1421,7 @@ def test_transport_get_channel(): [ transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport, + transports.SessionsRestTransport, ], ) def test_transport_adc(transport_class): @@ -1102,6 +1436,7 @@ def test_transport_adc(transport_class): "transport_name", [ "grpc", + "rest", ], ) def test_transport_kind(transport_name): @@ -1246,6 +1581,7 @@ def test_sessions_transport_auth_adc(transport_class): [ transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport, + transports.SessionsRestTransport, ], ) def test_sessions_transport_auth_gdch_credentials(transport_class): @@ -1343,11 +1679,23 @@ def test_sessions_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_sessions_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.SessionsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_sessions_host_no_port(transport_name): @@ -1358,7 +1706,11 @@ def test_sessions_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -1366,6 +1718,7 @@ def test_sessions_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_sessions_host_with_port(transport_name): @@ -1376,7 +1729,36 @@ def test_sessions_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_sessions_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = SessionsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = SessionsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.detect_intent._session + session2 = client2.transport.detect_intent._session + assert session1 != session2 + session1 = client1.transport.streaming_detect_intent._session + session2 = client2.transport.streaming_detect_intent._session + assert session1 != session2 def test_sessions_grpc_transport_channel(): @@ -1763,6 +2145,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = SessionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = SessionsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2480,6 +3148,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -2497,6 +3166,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: diff --git a/tests/unit/gapic/dialogflow_v2beta1/test_versions.py b/tests/unit/gapic/dialogflow_v2beta1/test_versions.py index 056be0d74..3dddce24d 100644 --- a/tests/unit/gapic/dialogflow_v2beta1/test_versions.py +++ b/tests/unit/gapic/dialogflow_v2beta1/test_versions.py @@ -22,6 +22,8 @@ except ImportError: # pragma: NO COVER import mock +from collections.abc import Iterable +import json import math from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template @@ -34,12 +36,15 @@ from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import json_format from google.protobuf import timestamp_pb2 # type: ignore import grpc from grpc.experimental import aio from proto.marshal.rules import wrappers from proto.marshal.rules.dates import DurationRule, TimestampRule import pytest +from requests import PreparedRequest, Request, Response +from requests.sessions import Session from google.cloud.dialogflow_v2beta1.services.versions import ( VersionsAsyncClient, @@ -95,6 +100,7 @@ def test__get_default_mtls_endpoint(): [ (VersionsClient, "grpc"), (VersionsAsyncClient, "grpc_asyncio"), + (VersionsClient, "rest"), ], ) def test_versions_client_from_service_account_info(client_class, transport_name): @@ -108,7 +114,11 @@ def test_versions_client_from_service_account_info(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -116,6 +126,7 @@ def test_versions_client_from_service_account_info(client_class, transport_name) [ (transports.VersionsGrpcTransport, "grpc"), (transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (transports.VersionsRestTransport, "rest"), ], ) def test_versions_client_service_account_always_use_jwt( @@ -141,6 +152,7 @@ def test_versions_client_service_account_always_use_jwt( [ (VersionsClient, "grpc"), (VersionsAsyncClient, "grpc_asyncio"), + (VersionsClient, "rest"), ], ) def test_versions_client_from_service_account_file(client_class, transport_name): @@ -161,13 +173,18 @@ def test_versions_client_from_service_account_file(client_class, transport_name) assert client.transport._credentials == creds assert isinstance(client, client_class) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) def test_versions_client_get_transport_class(): transport = VersionsClient.get_transport_class() available_transports = [ transports.VersionsGrpcTransport, + transports.VersionsRestTransport, ] assert transport in available_transports @@ -180,6 +197,7 @@ def test_versions_client_get_transport_class(): [ (VersionsClient, transports.VersionsGrpcTransport, "grpc"), (VersionsAsyncClient, transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (VersionsClient, transports.VersionsRestTransport, "rest"), ], ) @mock.patch.object( @@ -321,6 +339,8 @@ def test_versions_client_client_options(client_class, transport_class, transport "grpc_asyncio", "false", ), + (VersionsClient, transports.VersionsRestTransport, "rest", "true"), + (VersionsClient, transports.VersionsRestTransport, "rest", "false"), ], ) @mock.patch.object( @@ -510,6 +530,7 @@ def test_versions_client_get_mtls_endpoint_and_cert_source(client_class): [ (VersionsClient, transports.VersionsGrpcTransport, "grpc"), (VersionsAsyncClient, transports.VersionsGrpcAsyncIOTransport, "grpc_asyncio"), + (VersionsClient, transports.VersionsRestTransport, "rest"), ], ) def test_versions_client_client_options_scopes( @@ -545,6 +566,7 @@ def test_versions_client_client_options_scopes( "grpc_asyncio", grpc_helpers_async, ), + (VersionsClient, transports.VersionsRestTransport, "rest", None), ], ) def test_versions_client_client_options_credentials_file( @@ -2033,171 +2055,1603 @@ async def test_delete_version_flattened_error_async(): ) -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.VersionsGrpcTransport( +@pytest.mark.parametrize( + "request_type", + [ + version.ListVersionsRequest, + dict, + ], +) +def test_list_versions_rest(request_type): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = VersionsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = version.ListVersionsResponse( + next_page_token="next_page_token_value", ) - # It is an error to provide a credentials file and a transport instance. - transport = transports.VersionsGrpcTransport( + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.ListVersionsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.list_versions(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListVersionsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_versions_rest_required_fields(request_type=version.ListVersionsRequest): + transport_class = transports.VersionsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_versions._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).list_versions._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "page_size", + "page_token", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - with pytest.raises(ValueError): - client = VersionsClient( - client_options={"credentials_file": "credentials.json"}, - transport=transport, + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = version.ListVersionsResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = version.ListVersionsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_versions(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_list_versions_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.list_versions._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "pageSize", + "pageToken", + ) ) + & set(("parent",)) + ) - # It is an error to provide an api_key and a transport instance. - transport = transports.VersionsGrpcTransport( + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_list_versions_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), ) - options = client_options.ClientOptions() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = VersionsClient( - client_options=options, - transport=transport, + client = VersionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.VersionsRestInterceptor, "post_list_versions" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_list_versions" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.ListVersionsRequest.pb(version.ListVersionsRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = version.ListVersionsResponse.to_json( + version.ListVersionsResponse() ) - # It is an error to provide an api_key and a credential. - options = mock.Mock() - options.api_key = "api_key" - with pytest.raises(ValueError): - client = VersionsClient( - client_options=options, credentials=ga_credentials.AnonymousCredentials() + request = version.ListVersionsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = version.ListVersionsResponse() + + client.list_versions( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], ) - # It is an error to provide scopes and a transport instance. - transport = transports.VersionsGrpcTransport( + pre.assert_called_once() + post.assert_called_once() + + +def test_list_versions_rest_bad_request( + transport: str = "rest", request_type=version.ListVersionsRequest +): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - with pytest.raises(ValueError): - client = VersionsClient( - client_options={"scopes": ["1", "2"]}, - transport=transport, - ) + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request = request_type(**request_init) -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.VersionsGrpcTransport( + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_versions(request) + + +def test_list_versions_rest_flattened(): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport="rest", ) - client = VersionsClient(transport=transport) - assert client.transport is transport + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = version.ListVersionsResponse() -def test_transport_get_channel(): - # A client may be instantiated with a custom transport instance. - transport = transports.VersionsGrpcTransport( + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.ListVersionsResponse.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.list_versions(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent}/versions" % client.transport._host, + args[1], + ) + + +def test_list_versions_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel - transport = transports.VersionsGrpcAsyncIOTransport( + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_versions( + version.ListVersionsRequest(), + parent="parent_value", + ) + + +def test_list_versions_rest_pager(transport: str = "rest"): + client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - channel = transport.grpc_channel - assert channel + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # TODO(kbandes): remove this mock unless there's a good reason for it. + # with mock.patch.object(path_template, 'transcode') as transcode: + # Set the response as a series of pages + response = ( + version.ListVersionsResponse( + versions=[ + version.Version(), + version.Version(), + version.Version(), + ], + next_page_token="abc", + ), + version.ListVersionsResponse( + versions=[], + next_page_token="def", + ), + version.ListVersionsResponse( + versions=[ + version.Version(), + ], + next_page_token="ghi", + ), + version.ListVersionsResponse( + versions=[ + version.Version(), + version.Version(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple(version.ListVersionsResponse.to_json(x) for x in response) + return_values = tuple(Response() for i in response) + for return_val, response_val in zip(return_values, response): + return_val._content = response_val.encode("UTF-8") + return_val.status_code = 200 + req.side_effect = return_values -@pytest.mark.parametrize( - "transport_class", - [ - transports.VersionsGrpcTransport, - transports.VersionsGrpcAsyncIOTransport, - ], -) -def test_transport_adc(transport_class): - # Test default credentials are used if not provided. - with mock.patch.object(google.auth, "default") as adc: - adc.return_value = (ga_credentials.AnonymousCredentials(), None) - transport_class() - adc.assert_called_once() + sample_request = {"parent": "projects/sample1/agent"} + + pager = client.list_versions(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, version.Version) for i in results) + + pages = list(client.list_versions(request=sample_request).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.parametrize( - "transport_name", + "request_type", [ - "grpc", + version.GetVersionRequest, + dict, ], ) -def test_transport_kind(transport_name): - transport = VersionsClient.get_transport_class(transport_name)( - credentials=ga_credentials.AnonymousCredentials(), - ) - assert transport.kind == transport_name - - -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. +def test_get_version_rest(request_type): client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), - ) - assert isinstance( - client.transport, - transports.VersionsGrpcTransport, + transport="rest", ) + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/versions/sample2"} + request = request_type(**request_init) -def test_versions_base_transport_error(): - # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(core_exceptions.DuplicateCredentialArgs): - transport = transports.VersionsTransport( - credentials=ga_credentials.AnonymousCredentials(), - credentials_file="credentials.json", + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = version.Version( + name="name_value", + description="description_value", + version_number=1518, + status=version.Version.VersionStatus.IN_PROGRESS, ) + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) -def test_versions_base_transport(): - # Instantiate the base transport. - with mock.patch( - "google.cloud.dialogflow_v2beta1.services.versions.transports.VersionsTransport.__init__" - ) as Transport: - Transport.return_value = None - transport = transports.VersionsTransport( - credentials=ga_credentials.AnonymousCredentials(), - ) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.get_version(request) - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_versions", - "get_version", - "create_version", - "update_version", - "delete_version", - "get_location", - "list_locations", - "get_operation", - "cancel_operation", - "list_operations", + # Establish that the response is the type that we expect. + assert isinstance(response, version.Version) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.version_number == 1518 + assert response.status == version.Version.VersionStatus.IN_PROGRESS + + +def test_get_version_rest_required_fields(request_type=version.GetVersionRequest): + transport_class = transports.VersionsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - with pytest.raises(NotImplementedError): - transport.close() + # verify fields with default values are dropped - # Catch all for all remaining methods and properties - remainder = [ - "kind", - ] - for r in remainder: - with pytest.raises(NotImplementedError): - getattr(transport, r)() + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + # verify required fields with default values are now present -def test_versions_base_transport_with_credentials_file(): + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = version.Version() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_get_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_version._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_get_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.VersionsRestInterceptor, "post_get_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_get_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = version.GetVersionRequest.pb(version.GetVersionRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = version.Version.to_json(version.Version()) + + request = version.GetVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = version.Version() + + client.get_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_get_version_rest_bad_request( + transport: str = "rest", request_type=version.GetVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/versions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_version(request) + + +def test_get_version_rest_flattened(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = version.Version() + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/versions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.get_version(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/agent/versions/*}" % client.transport._host, + args[1], + ) + + +def test_get_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_version( + version.GetVersionRequest(), + name="name_value", + ) + + +def test_get_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_version.CreateVersionRequest, + dict, + ], +) +def test_create_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["version"] = { + "name": "name_value", + "description": "description_value", + "version_number": 1518, + "create_time": {"seconds": 751, "nanos": 543}, + "status": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version( + name="name_value", + description="description_value", + version_number=1518, + status=gcd_version.Version.VersionStatus.IN_PROGRESS, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.create_version(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_version.Version) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.version_number == 1518 + assert response.status == gcd_version.Version.VersionStatus.IN_PROGRESS + + +def test_create_version_rest_required_fields( + request_type=gcd_version.CreateVersionRequest, +): + transport_class = transports.VersionsRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.create_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_version._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "version", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.VersionsRestInterceptor, "post_create_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_create_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_version.CreateVersionRequest.pb( + gcd_version.CreateVersionRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_version.Version.to_json(gcd_version.Version()) + + request = gcd_version.CreateVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_version.Version() + + client.create_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_version_rest_bad_request( + transport: str = "rest", request_type=gcd_version.CreateVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"parent": "projects/sample1/agent"} + request_init["version"] = { + "name": "name_value", + "description": "description_value", + "version_number": 1518, + "create_time": {"seconds": 751, "nanos": 543}, + "status": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.create_version(request) + + +def test_create_version_rest_flattened(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/agent"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + version=gcd_version.Version(name="name_value"), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.create_version(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{parent=projects/*/agent}/versions" % client.transport._host, + args[1], + ) + + +def test_create_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_version( + gcd_version.CreateVersionRequest(), + parent="parent_value", + version=gcd_version.Version(name="name_value"), + ) + + +def test_create_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gcd_version.UpdateVersionRequest, + dict, + ], +) +def test_update_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"version": {"name": "projects/sample1/agent/versions/sample2"}} + request_init["version"] = { + "name": "projects/sample1/agent/versions/sample2", + "description": "description_value", + "version_number": 1518, + "create_time": {"seconds": 751, "nanos": 543}, + "status": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version( + name="name_value", + description="description_value", + version_number=1518, + status=gcd_version.Version.VersionStatus.IN_PROGRESS, + ) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.update_version(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, gcd_version.Version) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.version_number == 1518 + assert response.status == gcd_version.Version.VersionStatus.IN_PROGRESS + + +def test_update_version_rest_required_fields( + request_type=gcd_version.UpdateVersionRequest, +): + transport_class = transports.VersionsRestTransport + + request_init = {} + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).update_version._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("update_mask",)) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "patch", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.update_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_update_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.update_version._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(("updateMask",)) + & set( + ( + "version", + "updateMask", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_update_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.VersionsRestInterceptor, "post_update_version" + ) as post, mock.patch.object( + transports.VersionsRestInterceptor, "pre_update_version" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = gcd_version.UpdateVersionRequest.pb( + gcd_version.UpdateVersionRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + req.return_value._content = gcd_version.Version.to_json(gcd_version.Version()) + + request = gcd_version.UpdateVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = gcd_version.Version() + + client.update_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_update_version_rest_bad_request( + transport: str = "rest", request_type=gcd_version.UpdateVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"version": {"name": "projects/sample1/agent/versions/sample2"}} + request_init["version"] = { + "name": "projects/sample1/agent/versions/sample2", + "description": "description_value", + "version_number": 1518, + "create_time": {"seconds": 751, "nanos": 543}, + "status": 1, + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.update_version(request) + + +def test_update_version_rest_flattened(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcd_version.Version() + + # get arguments that satisfy an http rule for this method + sample_request = { + "version": {"name": "projects/sample1/agent/versions/sample2"} + } + + # get truthy value for each flattened field + mock_args = dict( + version=gcd_version.Version(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + pb_return_value = gcd_version.Version.pb(return_value) + json_return_value = json_format.MessageToJson(pb_return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.update_version(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{version.name=projects/*/agent/versions/*}" + % client.transport._host, + args[1], + ) + + +def test_update_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_version( + gcd_version.UpdateVersionRequest(), + version=gcd_version.Version(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +def test_update_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +@pytest.mark.parametrize( + "request_type", + [ + version.DeleteVersionRequest, + dict, + ], +) +def test_delete_version_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/versions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_version(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_version_rest_required_fields(request_type=version.DeleteVersionRequest): + transport_class = transports.VersionsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson( + pb_request, + including_default_value_fields=False, + use_integers_for_enums=False, + ) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).delete_version._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = None + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "delete", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.delete_version(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_delete_version_rest_unset_required_fields(): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.delete_version._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_version_rest_interceptors(null_interceptor): + transport = transports.VersionsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None if null_interceptor else transports.VersionsRestInterceptor(), + ) + client = VersionsClient(transport=transport) + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.VersionsRestInterceptor, "pre_delete_version" + ) as pre: + pre.assert_not_called() + pb_message = version.DeleteVersionRequest.pb(version.DeleteVersionRequest()) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = Response() + req.return_value.status_code = 200 + req.return_value.request = PreparedRequest() + + request = version.DeleteVersionRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_version( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + +def test_delete_version_rest_bad_request( + transport: str = "rest", request_type=version.DeleteVersionRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/agent/versions/sample2"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.delete_version(request) + + +def test_delete_version_rest_flattened(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # get arguments that satisfy an http rule for this method + sample_request = {"name": "projects/sample1/agent/versions/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "" + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + client.delete_version(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v2beta1/{name=projects/*/agent/versions/*}" % client.transport._host, + args[1], + ) + + +def test_delete_version_rest_flattened_error(transport: str = "rest"): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_version( + version.DeleteVersionRequest(), + name="name_value", + ) + + +def test_delete_version_rest_error(): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = VersionsClient( + client_options=options, + transport=transport, + ) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = VersionsClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = VersionsClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = VersionsClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.VersionsGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.VersionsGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.VersionsGrpcTransport, + transports.VersionsGrpcAsyncIOTransport, + transports.VersionsRestTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "rest", + ], +) +def test_transport_kind(transport_name): + transport = VersionsClient.get_transport_class(transport_name)( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert transport.kind == transport_name + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.VersionsGrpcTransport, + ) + + +def test_versions_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.VersionsTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_versions_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflow_v2beta1.services.versions.transports.VersionsTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.VersionsTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_versions", + "get_version", + "create_version", + "update_version", + "delete_version", + "get_location", + "list_locations", + "get_operation", + "cancel_operation", + "list_operations", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + with pytest.raises(NotImplementedError): + transport.close() + + # Catch all for all remaining methods and properties + remainder = [ + "kind", + ] + for r in remainder: + with pytest.raises(NotImplementedError): + getattr(transport, r)() + + +def test_versions_base_transport_with_credentials_file(): # Instantiate the base transport with a credentials file with mock.patch.object( google.auth, "load_credentials_from_file", autospec=True @@ -2275,6 +3729,7 @@ def test_versions_transport_auth_adc(transport_class): [ transports.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport, + transports.VersionsRestTransport, ], ) def test_versions_transport_auth_gdch_credentials(transport_class): @@ -2372,11 +3827,23 @@ def test_versions_grpc_transport_client_cert_source_for_mtls(transport_class): ) +def test_versions_http_transport_client_cert_source_for_mtls(): + cred = ga_credentials.AnonymousCredentials() + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.configure_mtls_channel" + ) as mock_configure_mtls_channel: + transports.VersionsRestTransport( + credentials=cred, client_cert_source_for_mtls=client_cert_source_callback + ) + mock_configure_mtls_channel.assert_called_once_with(client_cert_source_callback) + + @pytest.mark.parametrize( "transport_name", [ "grpc", "grpc_asyncio", + "rest", ], ) def test_versions_host_no_port(transport_name): @@ -2387,7 +3854,11 @@ def test_versions_host_no_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:443") + assert client.transport._host == ( + "dialogflow.googleapis.com:443" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com" + ) @pytest.mark.parametrize( @@ -2395,6 +3866,7 @@ def test_versions_host_no_port(transport_name): [ "grpc", "grpc_asyncio", + "rest", ], ) def test_versions_host_with_port(transport_name): @@ -2405,7 +3877,45 @@ def test_versions_host_with_port(transport_name): ), transport=transport_name, ) - assert client.transport._host == ("dialogflow.googleapis.com:8000") + assert client.transport._host == ( + "dialogflow.googleapis.com:8000" + if transport_name in ["grpc", "grpc_asyncio"] + else "https://dialogflow.googleapis.com:8000" + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "rest", + ], +) +def test_versions_client_transport_session_collision(transport_name): + creds1 = ga_credentials.AnonymousCredentials() + creds2 = ga_credentials.AnonymousCredentials() + client1 = VersionsClient( + credentials=creds1, + transport=transport_name, + ) + client2 = VersionsClient( + credentials=creds2, + transport=transport_name, + ) + session1 = client1.transport.list_versions._session + session2 = client2.transport.list_versions._session + assert session1 != session2 + session1 = client1.transport.get_version._session + session2 = client2.transport.get_version._session + assert session1 != session2 + session1 = client1.transport.create_version._session + session2 = client2.transport.create_version._session + assert session1 != session2 + session1 = client1.transport.update_version._session + session2 = client2.transport.update_version._session + assert session1 != session2 + session1 = client1.transport.delete_version._session + session2 = client2.transport.delete_version._session + assert session1 != session2 def test_versions_grpc_transport_channel(): @@ -2689,6 +4199,292 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_location_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.GetLocationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/locations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_location(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.GetLocationRequest, + dict, + ], +) +def test_get_location_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/locations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.Location() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_location(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.Location) + + +def test_list_locations_rest_bad_request( + transport: str = "rest", request_type=locations_pb2.ListLocationsRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_locations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + locations_pb2.ListLocationsRequest, + dict, + ], +) +def test_list_locations_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = locations_pb2.ListLocationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_locations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, locations_pb2.ListLocationsResponse) + + +def test_cancel_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.CancelOperationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.cancel_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.CancelOperationRequest, + dict, + ], +) +def test_cancel_operation_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = "{}" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.cancel_operation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_get_operation_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.GetOperationRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict( + {"name": "projects/sample1/operations/sample2"}, request + ) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.get_operation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.GetOperationRequest, + dict, + ], +) +def test_get_operation_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1/operations/sample2"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.get_operation(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_list_operations_rest_bad_request( + transport: str = "rest", request_type=operations_pb2.ListOperationsRequest +): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + request = request_type() + request = json_format.ParseDict({"name": "projects/sample1"}, request) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 400 + response_value.request = Request() + req.return_value = response_value + client.list_operations(request) + + +@pytest.mark.parametrize( + "request_type", + [ + operations_pb2.ListOperationsRequest, + dict, + ], +) +def test_list_operations_rest(request_type): + client = VersionsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request_init = {"name": "projects/sample1"} + request = request_type(**request_init) + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.ListOperationsResponse() + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + + response = client.list_operations(request) + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + def test_cancel_operation(transport: str = "grpc"): client = VersionsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3406,6 +5202,7 @@ async def test_get_location_from_dict_async(): def test_transport_close(): transports = { + "rest": "_session", "grpc": "_grpc_channel", } @@ -3423,6 +5220,7 @@ def test_transport_close(): def test_client_ctx(): transports = [ + "rest", "grpc", ] for transport in transports: From 891262a6feadf2b2a703ffe7ad361c2eff5834d8 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 10:01:14 -0800 Subject: [PATCH 10/10] chore(main): release 2.20.0 (#625) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ google/cloud/dialogflow/gapic_version.py | 2 +- google/cloud/dialogflow_v2/gapic_version.py | 2 +- google/cloud/dialogflow_v2beta1/gapic_version.py | 2 +- ...snippet_metadata_google.cloud.dialogflow.v2.json | 2 +- ...et_metadata_google.cloud.dialogflow.v2beta1.json | 2 +- 7 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b1f180928..da2177c62 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.19.1" + ".": "2.20.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 86ce1a35a..188af1327 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ [1]: https://pypi.org/project/dialogflow/#history +## [2.20.0](https://github.com/googleapis/python-dialogflow/compare/v2.19.1...v2.20.0) (2023-02-28) + + +### Features + +* Added support for AssistQueryParameters and SynthesizeSpeechConfig ([03199c4](https://github.com/googleapis/python-dialogflow/commit/03199c43fd509bd7bd2693ce6648e9defbea3cf2)) +* Enable "rest" transport in Python for services supporting numeric enums ([03199c4](https://github.com/googleapis/python-dialogflow/commit/03199c43fd509bd7bd2693ce6648e9defbea3cf2)) + + +### Documentation + +* Add more meaningful comments ([03199c4](https://github.com/googleapis/python-dialogflow/commit/03199c43fd509bd7bd2693ce6648e9defbea3cf2)) + ## [2.19.1](https://github.com/googleapis/python-dialogflow/compare/v2.19.0...v2.19.1) (2023-01-20) diff --git a/google/cloud/dialogflow/gapic_version.py b/google/cloud/dialogflow/gapic_version.py index c5d0439f6..551f0d2eb 100644 --- a/google/cloud/dialogflow/gapic_version.py +++ b/google/cloud/dialogflow/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.19.1" # {x-release-please-version} +__version__ = "2.20.0" # {x-release-please-version} diff --git a/google/cloud/dialogflow_v2/gapic_version.py b/google/cloud/dialogflow_v2/gapic_version.py index c5d0439f6..551f0d2eb 100644 --- a/google/cloud/dialogflow_v2/gapic_version.py +++ b/google/cloud/dialogflow_v2/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.19.1" # {x-release-please-version} +__version__ = "2.20.0" # {x-release-please-version} diff --git a/google/cloud/dialogflow_v2beta1/gapic_version.py b/google/cloud/dialogflow_v2beta1/gapic_version.py index c5d0439f6..551f0d2eb 100644 --- a/google/cloud/dialogflow_v2beta1/gapic_version.py +++ b/google/cloud/dialogflow_v2beta1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "2.19.1" # {x-release-please-version} +__version__ = "2.20.0" # {x-release-please-version} diff --git a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2.json b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2.json index 43eb1e2b9..cbb2dfa6e 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dialogflow", - "version": "0.1.0" + "version": "2.20.0" }, "snippets": [ { diff --git a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2beta1.json b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2beta1.json index 748920df0..c5d24d222 100644 --- a/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2beta1.json +++ b/samples/generated_samples/snippet_metadata_google.cloud.dialogflow.v2beta1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-cloud-dialogflow", - "version": "0.1.0" + "version": "2.20.0" }, "snippets": [ {