diff --git a/google/cloud/datastore_admin_v1/services/datastore_admin/async_client.py b/google/cloud/datastore_admin_v1/services/datastore_admin/async_client.py index 0f6be699..2a7e46c4 100644 --- a/google/cloud/datastore_admin_v1/services/datastore_admin/async_client.py +++ b/google/cloud/datastore_admin_v1/services/datastore_admin/async_client.py @@ -287,11 +287,18 @@ async def export_entities( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 - def sample_export_entities(): + async def sample_export_entities(): # Create a client - client = datastore_admin_v1.DatastoreAdminClient() + client = datastore_admin_v1.DatastoreAdminAsyncClient() # Initialize request argument(s) request = datastore_admin_v1.ExportEntitiesRequest( @@ -304,7 +311,7 @@ def sample_export_entities(): print("Waiting for operation to complete...") - response = operation.result() + response = await operation.result() # Handle the response print(response) @@ -409,6 +416,14 @@ def sample_export_entities(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = await rpc( request, @@ -450,11 +465,18 @@ async def import_entities( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 - def sample_import_entities(): + async def sample_import_entities(): # Create a client - client = datastore_admin_v1.DatastoreAdminClient() + client = datastore_admin_v1.DatastoreAdminAsyncClient() # Initialize request argument(s) request = datastore_admin_v1.ImportEntitiesRequest( @@ -467,7 +489,7 @@ def sample_import_entities(): print("Waiting for operation to complete...") - response = operation.result() + response = await operation.result() # Handle the response print(response) @@ -540,9 +562,6 @@ def sample_import_entities(): } - The JSON representation for Empty is empty JSON - object {}. - """ # Create or coerce a protobuf request object. # Quick check: If we got a request object, we should *not* have @@ -576,6 +595,14 @@ def sample_import_entities(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = await rpc( request, @@ -621,11 +648,18 @@ async def create_index( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 - def sample_create_index(): + async def sample_create_index(): # Create a client - client = datastore_admin_v1.DatastoreAdminClient() + client = datastore_admin_v1.DatastoreAdminAsyncClient() # Initialize request argument(s) request = datastore_admin_v1.CreateIndexRequest( @@ -636,7 +670,7 @@ def sample_create_index(): print("Waiting for operation to complete...") - response = operation.result() + response = await operation.result() # Handle the response print(response) @@ -671,6 +705,14 @@ def sample_create_index(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = await rpc( request, @@ -715,11 +757,18 @@ async def delete_index( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 - def sample_delete_index(): + async def sample_delete_index(): # Create a client - client = datastore_admin_v1.DatastoreAdminClient() + client = datastore_admin_v1.DatastoreAdminAsyncClient() # Initialize request argument(s) request = datastore_admin_v1.DeleteIndexRequest( @@ -730,7 +779,7 @@ def sample_delete_index(): print("Waiting for operation to complete...") - response = operation.result() + response = await operation.result() # Handle the response print(response) @@ -765,6 +814,17 @@ def sample_delete_index(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + ( + ("project_id", request.project_id), + ("index_id", request.index_id), + ) + ), + ) + # Send the request. response = await rpc( request, @@ -796,18 +856,25 @@ async def get_index( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 - def sample_get_index(): + async def sample_get_index(): # Create a client - client = datastore_admin_v1.DatastoreAdminClient() + client = datastore_admin_v1.DatastoreAdminAsyncClient() # Initialize request argument(s) request = datastore_admin_v1.GetIndexRequest( ) # Make the request - response = client.get_index(request=request) + response = await client.get_index(request=request) # Handle the response print(response) @@ -847,6 +914,17 @@ def sample_get_index(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + ( + ("project_id", request.project_id), + ("index_id", request.index_id), + ) + ), + ) + # Send the request. response = await rpc( request, @@ -873,11 +951,18 @@ async def list_indexes( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 - def sample_list_indexes(): + async def sample_list_indexes(): # Create a client - client = datastore_admin_v1.DatastoreAdminClient() + client = datastore_admin_v1.DatastoreAdminAsyncClient() # Initialize request argument(s) request = datastore_admin_v1.ListIndexesRequest( @@ -887,7 +972,7 @@ def sample_list_indexes(): page_result = client.list_indexes(request=request) # Handle the response - for response in page_result: + async for response in page_result: print(response) Args: @@ -930,6 +1015,14 @@ def sample_list_indexes(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = await rpc( request, diff --git a/google/cloud/datastore_admin_v1/services/datastore_admin/client.py b/google/cloud/datastore_admin_v1/services/datastore_admin/client.py index 8f5364a7..201a69e8 100644 --- a/google/cloud/datastore_admin_v1/services/datastore_admin/client.py +++ b/google/cloud/datastore_admin_v1/services/datastore_admin/client.py @@ -461,6 +461,7 @@ def __init__( quota_project_id=client_options.quota_project_id, client_info=client_info, always_use_jwt_access=True, + api_audience=client_options.api_audience, ) def export_entities( @@ -488,6 +489,13 @@ def export_entities( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 def sample_export_entities(): @@ -609,6 +617,14 @@ def sample_export_entities(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.export_entities] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = rpc( request, @@ -650,6 +666,13 @@ def import_entities( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 def sample_import_entities(): @@ -740,9 +763,6 @@ def sample_import_entities(): } - The JSON representation for Empty is empty JSON - object {}. - """ # Create or coerce a protobuf request object. # Quick check: If we got a request object, we should *not* have @@ -775,6 +795,14 @@ def sample_import_entities(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.import_entities] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = rpc( request, @@ -820,6 +848,13 @@ def create_index( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 def sample_create_index(): @@ -871,6 +906,14 @@ def sample_create_index(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.create_index] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = rpc( request, @@ -915,6 +958,13 @@ def delete_index( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 def sample_delete_index(): @@ -966,6 +1016,17 @@ def sample_delete_index(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.delete_index] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + ( + ("project_id", request.project_id), + ("index_id", request.index_id), + ) + ), + ) + # Send the request. response = rpc( request, @@ -997,6 +1058,13 @@ def get_index( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 def sample_get_index(): @@ -1039,6 +1107,17 @@ def sample_get_index(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.get_index] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + ( + ("project_id", request.project_id), + ("index_id", request.index_id), + ) + ), + ) + # Send the request. response = rpc( request, @@ -1065,6 +1144,13 @@ def list_indexes( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_admin_v1 def sample_list_indexes(): @@ -1113,6 +1199,14 @@ def sample_list_indexes(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.list_indexes] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = rpc( request, diff --git a/google/cloud/datastore_admin_v1/services/datastore_admin/transports/base.py b/google/cloud/datastore_admin_v1/services/datastore_admin/transports/base.py index 618a990c..cf9fd950 100644 --- a/google/cloud/datastore_admin_v1/services/datastore_admin/transports/base.py +++ b/google/cloud/datastore_admin_v1/services/datastore_admin/transports/base.py @@ -60,6 +60,7 @@ def __init__( quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, **kwargs, ) -> None: """Instantiate the transport. @@ -87,11 +88,6 @@ def __init__( be used for service account credentials. """ - # Save the hostname. Default to port 443 (HTTPS) if none is specified. - if ":" not in host: - host += ":443" - self._host = host - scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES} # Save the scopes. @@ -112,6 +108,11 @@ def __init__( credentials, _ = google.auth.default( **scopes_kwargs, quota_project_id=quota_project_id ) + # Don't apply audience if the credentials file passed from user. + if hasattr(credentials, "with_gdch_audience"): + credentials = credentials.with_gdch_audience( + api_audience if api_audience else host + ) # If the credentials are service account credentials, then always try to use self signed JWT. if ( @@ -124,6 +125,11 @@ def __init__( # Save the credentials. self._credentials = credentials + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { diff --git a/google/cloud/datastore_admin_v1/services/datastore_admin/transports/grpc.py b/google/cloud/datastore_admin_v1/services/datastore_admin/transports/grpc.py index e4193366..f15228fa 100644 --- a/google/cloud/datastore_admin_v1/services/datastore_admin/transports/grpc.py +++ b/google/cloud/datastore_admin_v1/services/datastore_admin/transports/grpc.py @@ -118,6 +118,7 @@ def __init__( quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, ) -> None: """Instantiate the transport. @@ -214,6 +215,7 @@ def __init__( quota_project_id=quota_project_id, client_info=client_info, always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, ) if not self._grpc_channel: diff --git a/google/cloud/datastore_admin_v1/services/datastore_admin/transports/grpc_asyncio.py b/google/cloud/datastore_admin_v1/services/datastore_admin/transports/grpc_asyncio.py index 46f84887..b5ec2814 100644 --- a/google/cloud/datastore_admin_v1/services/datastore_admin/transports/grpc_asyncio.py +++ b/google/cloud/datastore_admin_v1/services/datastore_admin/transports/grpc_asyncio.py @@ -163,6 +163,7 @@ def __init__( quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, ) -> None: """Instantiate the transport. @@ -259,6 +260,7 @@ def __init__( quota_project_id=quota_project_id, client_info=client_info, always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, ) if not self._grpc_channel: diff --git a/google/cloud/datastore_admin_v1/types/datastore_admin.py b/google/cloud/datastore_admin_v1/types/datastore_admin.py index 82bacec1..1bffdf3d 100644 --- a/google/cloud/datastore_admin_v1/types/datastore_admin.py +++ b/google/cloud/datastore_admin_v1/types/datastore_admin.py @@ -570,7 +570,7 @@ class DatastoreFirestoreMigrationMetadata(proto.Message): deviation from the LRO design pattern. This singleton resource can be accessed at: - ``projects/{project_id}/datastore-firestore-migration`` + "projects/{project_id}/operations/datastore-firestore-migration" Attributes: migration_state (google.cloud.datastore_admin_v1.types.MigrationState): diff --git a/google/cloud/datastore_admin_v1/types/migration.py b/google/cloud/datastore_admin_v1/types/migration.py index 97d4145f..cbd4f4f7 100644 --- a/google/cloud/datastore_admin_v1/types/migration.py +++ b/google/cloud/datastore_admin_v1/types/migration.py @@ -98,6 +98,7 @@ class ConcurrencyMode(proto.Enum): CONCURRENCY_MODE_UNSPECIFIED = 0 PESSIMISTIC = 1 OPTIMISTIC = 2 + OPTIMISTIC_WITH_ENTITY_GROUPS = 3 class PrepareStepDetails(proto.Message): r"""Details for the ``PREPARE`` step. diff --git a/google/cloud/datastore_v1/__init__.py b/google/cloud/datastore_v1/__init__.py index 881df4ca..83e7464d 100644 --- a/google/cloud/datastore_v1/__init__.py +++ b/google/cloud/datastore_v1/__init__.py @@ -17,6 +17,8 @@ from .services.datastore import DatastoreClient from .services.datastore import DatastoreAsyncClient +from .types.aggregation_result import AggregationResult +from .types.aggregation_result import AggregationResultBatch from .types.datastore import AllocateIdsRequest from .types.datastore import AllocateIdsResponse from .types.datastore import BeginTransactionRequest @@ -32,6 +34,8 @@ from .types.datastore import ReserveIdsResponse from .types.datastore import RollbackRequest from .types.datastore import RollbackResponse +from .types.datastore import RunAggregationQueryRequest +from .types.datastore import RunAggregationQueryResponse from .types.datastore import RunQueryRequest from .types.datastore import RunQueryResponse from .types.datastore import TransactionOptions @@ -40,6 +44,7 @@ from .types.entity import Key from .types.entity import PartitionId from .types.entity import Value +from .types.query import AggregationQuery from .types.query import CompositeFilter from .types.query import EntityResult from .types.query import Filter @@ -55,6 +60,9 @@ __all__ = ( "DatastoreAsyncClient", + "AggregationQuery", + "AggregationResult", + "AggregationResultBatch", "AllocateIdsRequest", "AllocateIdsResponse", "ArrayValue", @@ -87,6 +95,8 @@ "ReserveIdsResponse", "RollbackRequest", "RollbackResponse", + "RunAggregationQueryRequest", + "RunAggregationQueryResponse", "RunQueryRequest", "RunQueryResponse", "TransactionOptions", diff --git a/google/cloud/datastore_v1/gapic_metadata.json b/google/cloud/datastore_v1/gapic_metadata.json index 5da47e53..ddde2b76 100644 --- a/google/cloud/datastore_v1/gapic_metadata.json +++ b/google/cloud/datastore_v1/gapic_metadata.json @@ -40,6 +40,11 @@ "rollback" ] }, + "RunAggregationQuery": { + "methods": [ + "run_aggregation_query" + ] + }, "RunQuery": { "methods": [ "run_query" @@ -80,6 +85,11 @@ "rollback" ] }, + "RunAggregationQuery": { + "methods": [ + "run_aggregation_query" + ] + }, "RunQuery": { "methods": [ "run_query" diff --git a/google/cloud/datastore_v1/services/datastore/async_client.py b/google/cloud/datastore_v1/services/datastore/async_client.py index ab4d60cc..c6e6f2df 100644 --- a/google/cloud/datastore_v1/services/datastore/async_client.py +++ b/google/cloud/datastore_v1/services/datastore/async_client.py @@ -31,9 +31,11 @@ except AttributeError: # pragma: NO COVER OptionalRetry = Union[retries.Retry, object] # type: ignore +from google.cloud.datastore_v1.types import aggregation_result from google.cloud.datastore_v1.types import datastore from google.cloud.datastore_v1.types import entity from google.cloud.datastore_v1.types import query +from google.longrunning import operations_pb2 from google.protobuf import timestamp_pb2 # type: ignore from .transports.base import DatastoreTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import DatastoreGrpcAsyncIOTransport @@ -218,11 +220,18 @@ async def lookup( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 - def sample_lookup(): + async def sample_lookup(): # Create a client - client = datastore_v1.DatastoreClient() + client = datastore_v1.DatastoreAsyncClient() # Initialize request argument(s) request = datastore_v1.LookupRequest( @@ -230,7 +239,7 @@ def sample_lookup(): ) # Make the request - response = client.lookup(request=request) + response = await client.lookup(request=request) # Handle the response print(response) @@ -309,6 +318,14 @@ def sample_lookup(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = await rpc( request, @@ -332,11 +349,18 @@ async def run_query( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 - def sample_run_query(): + async def sample_run_query(): # Create a client - client = datastore_v1.DatastoreClient() + client = datastore_v1.DatastoreAsyncClient() # Initialize request argument(s) request = datastore_v1.RunQueryRequest( @@ -344,7 +368,7 @@ def sample_run_query(): ) # Make the request - response = client.run_query(request=request) + response = await client.run_query(request=request) # Handle the response print(response) @@ -386,6 +410,106 @@ def sample_run_query(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def run_aggregation_query( + self, + request: Union[datastore.RunAggregationQueryRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> datastore.RunAggregationQueryResponse: + r"""Runs an aggregation query. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import datastore_v1 + + async def sample_run_aggregation_query(): + # Create a client + client = datastore_v1.DatastoreAsyncClient() + + # Initialize request argument(s) + request = datastore_v1.RunAggregationQueryRequest( + project_id="project_id_value", + ) + + # Make the request + response = await client.run_aggregation_query(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.datastore_v1.types.RunAggregationQueryRequest, dict]): + The request object. The request for + [Datastore.RunAggregationQuery][google.datastore.v1.Datastore.RunAggregationQuery]. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.datastore_v1.types.RunAggregationQueryResponse: + The response for + [Datastore.RunAggregationQuery][google.datastore.v1.Datastore.RunAggregationQuery]. + + """ + # Create or coerce a protobuf request object. + request = datastore.RunAggregationQueryRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.run_aggregation_query, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = await rpc( request, @@ -410,11 +534,18 @@ async def begin_transaction( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 - def sample_begin_transaction(): + async def sample_begin_transaction(): # Create a client - client = datastore_v1.DatastoreClient() + client = datastore_v1.DatastoreAsyncClient() # Initialize request argument(s) request = datastore_v1.BeginTransactionRequest( @@ -422,7 +553,7 @@ def sample_begin_transaction(): ) # Make the request - response = client.begin_transaction(request=request) + response = await client.begin_transaction(request=request) # Handle the response print(response) @@ -475,6 +606,14 @@ def sample_begin_transaction(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = await rpc( request, @@ -503,11 +642,18 @@ async def commit( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 - def sample_commit(): + async def sample_commit(): # Create a client - client = datastore_v1.DatastoreClient() + client = datastore_v1.DatastoreAsyncClient() # Initialize request argument(s) request = datastore_v1.CommitRequest( @@ -516,7 +662,7 @@ def sample_commit(): ) # Make the request - response = client.commit(request=request) + response = await client.commit(request=request) # Handle the response print(response) @@ -610,6 +756,14 @@ def sample_commit(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = await rpc( request, @@ -635,11 +789,18 @@ async def rollback( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 - def sample_rollback(): + async def sample_rollback(): # Create a client - client = datastore_v1.DatastoreClient() + client = datastore_v1.DatastoreAsyncClient() # Initialize request argument(s) request = datastore_v1.RollbackRequest( @@ -648,7 +809,7 @@ def sample_rollback(): ) # Make the request - response = client.rollback(request=request) + response = await client.rollback(request=request) # Handle the response print(response) @@ -711,6 +872,14 @@ def sample_rollback(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = await rpc( request, @@ -737,11 +906,18 @@ async def allocate_ids( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 - def sample_allocate_ids(): + async def sample_allocate_ids(): # Create a client - client = datastore_v1.DatastoreClient() + client = datastore_v1.DatastoreAsyncClient() # Initialize request argument(s) request = datastore_v1.AllocateIdsRequest( @@ -749,7 +925,7 @@ def sample_allocate_ids(): ) # Make the request - response = client.allocate_ids(request=request) + response = await client.allocate_ids(request=request) # Handle the response print(response) @@ -813,6 +989,14 @@ def sample_allocate_ids(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = await rpc( request, @@ -839,11 +1023,18 @@ async def reserve_ids( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 - def sample_reserve_ids(): + async def sample_reserve_ids(): # Create a client - client = datastore_v1.DatastoreClient() + client = datastore_v1.DatastoreAsyncClient() # Initialize request argument(s) request = datastore_v1.ReserveIdsRequest( @@ -851,7 +1042,7 @@ def sample_reserve_ids(): ) # Make the request - response = client.reserve_ids(request=request) + response = await client.reserve_ids(request=request) # Handle the response print(response) @@ -924,6 +1115,14 @@ def sample_reserve_ids(): client_info=DEFAULT_CLIENT_INFO, ) + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = await rpc( request, @@ -935,6 +1134,223 @@ def sample_reserve_ids(): # Done; return the response. return response + async def list_operations( + self, + request: operations_pb2.ListOperationsRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. + + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message 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 message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_operation( + self, + request: operations_pb2.GetOperationRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message 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: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_operation( + self, + request: operations_pb2.DeleteOperationRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` 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: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def cancel_operation( + self, + request: operations_pb2.CancelOperationRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Starts asynchronous cancellation on a long-running operation. + + The server makes a best effort to cancel the operation, but success + is not guaranteed. If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.CancelOperationRequest`): + The request object. Request message 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. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.CancelOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._client._transport.cancel_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + async def __aenter__(self): return self diff --git a/google/cloud/datastore_v1/services/datastore/client.py b/google/cloud/datastore_v1/services/datastore/client.py index 5b012a2f..4d0b8f34 100644 --- a/google/cloud/datastore_v1/services/datastore/client.py +++ b/google/cloud/datastore_v1/services/datastore/client.py @@ -34,9 +34,11 @@ except AttributeError: # pragma: NO COVER OptionalRetry = Union[retries.Retry, object] # type: ignore +from google.cloud.datastore_v1.types import aggregation_result from google.cloud.datastore_v1.types import datastore from google.cloud.datastore_v1.types import entity from google.cloud.datastore_v1.types import query +from google.longrunning import operations_pb2 from google.protobuf import timestamp_pb2 # type: ignore from .transports.base import DatastoreTransport, DEFAULT_CLIENT_INFO from .transports.grpc import DatastoreGrpcTransport @@ -409,6 +411,7 @@ def __init__( quota_project_id=client_options.quota_project_id, client_info=client_info, always_use_jwt_access=True, + api_audience=client_options.api_audience, ) def lookup( @@ -426,6 +429,13 @@ def lookup( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 def sample_lookup(): @@ -507,6 +517,14 @@ def sample_lookup(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.lookup] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = rpc( request, @@ -530,6 +548,13 @@ def run_query( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 def sample_run_query(): @@ -575,6 +600,97 @@ def sample_run_query(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.run_query] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def run_aggregation_query( + self, + request: Union[datastore.RunAggregationQueryRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> datastore.RunAggregationQueryResponse: + r"""Runs an aggregation query. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import datastore_v1 + + def sample_run_aggregation_query(): + # Create a client + client = datastore_v1.DatastoreClient() + + # Initialize request argument(s) + request = datastore_v1.RunAggregationQueryRequest( + project_id="project_id_value", + ) + + # Make the request + response = client.run_aggregation_query(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.datastore_v1.types.RunAggregationQueryRequest, dict]): + The request object. The request for + [Datastore.RunAggregationQuery][google.datastore.v1.Datastore.RunAggregationQuery]. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.datastore_v1.types.RunAggregationQueryResponse: + The response for + [Datastore.RunAggregationQuery][google.datastore.v1.Datastore.RunAggregationQuery]. + + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a datastore.RunAggregationQueryRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, datastore.RunAggregationQueryRequest): + request = datastore.RunAggregationQueryRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.run_aggregation_query] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = rpc( request, @@ -599,6 +715,13 @@ def begin_transaction( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 def sample_begin_transaction(): @@ -664,6 +787,14 @@ def sample_begin_transaction(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.begin_transaction] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = rpc( request, @@ -692,6 +823,13 @@ def commit( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 def sample_commit(): @@ -799,6 +937,14 @@ def sample_commit(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.commit] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = rpc( request, @@ -824,6 +970,13 @@ def rollback( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 def sample_rollback(): @@ -900,6 +1053,14 @@ def sample_rollback(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.rollback] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = rpc( request, @@ -926,6 +1087,13 @@ def allocate_ids( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 def sample_allocate_ids(): @@ -1002,6 +1170,14 @@ def sample_allocate_ids(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.allocate_ids] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = rpc( request, @@ -1028,6 +1204,13 @@ def reserve_ids( .. code-block:: python + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html from google.cloud import datastore_v1 def sample_reserve_ids(): @@ -1103,6 +1286,14 @@ def sample_reserve_ids(): # and friendly error handling. rpc = self._transport._wrapped_methods[self._transport.reserve_ids] + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("project_id", request.project_id),) + ), + ) + # Send the request. response = rpc( request, @@ -1127,6 +1318,223 @@ def __exit__(self, type, value, traceback): """ self.transport.close() + def list_operations( + self, + request: operations_pb2.ListOperationsRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.ListOperationsResponse: + r"""Lists operations that match the specified filter in the request. + + Args: + request (:class:`~.operations_pb2.ListOperationsRequest`): + The request object. Request message 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 message for ``ListOperations`` method. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.ListOperationsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.list_operations, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_operation( + self, + request: operations_pb2.GetOperationRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Gets the latest state of a long-running operation. + + Args: + request (:class:`~.operations_pb2.GetOperationRequest`): + The request object. Request message 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: + An ``Operation`` object. + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.GetOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.get_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_operation( + self, + request: operations_pb2.DeleteOperationRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a long-running operation. + + This method indicates that the client is no longer interested + in the operation result. It does not cancel the operation. + If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.DeleteOperationRequest`): + The request object. Request message for + `DeleteOperation` 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: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.DeleteOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.delete_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + def cancel_operation( + self, + request: operations_pb2.CancelOperationRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Starts asynchronous cancellation on a long-running operation. + + The server makes a best effort to cancel the operation, but success + is not guaranteed. If the server doesn't support this method, it returns + `google.rpc.Code.UNIMPLEMENTED`. + + Args: + request (:class:`~.operations_pb2.CancelOperationRequest`): + The request object. Request message 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. + Returns: + None + """ + # Create or coerce a protobuf request object. + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = operations_pb2.CancelOperationRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.cancel_operation, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/datastore_v1/services/datastore/transports/base.py b/google/cloud/datastore_v1/services/datastore/transports/base.py index 22a4c167..d628468b 100644 --- a/google/cloud/datastore_v1/services/datastore/transports/base.py +++ b/google/cloud/datastore_v1/services/datastore/transports/base.py @@ -26,6 +26,7 @@ from google.oauth2 import service_account # type: ignore from google.cloud.datastore_v1.types import datastore +from google.longrunning import operations_pb2 try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( @@ -57,6 +58,7 @@ def __init__( quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, **kwargs, ) -> None: """Instantiate the transport. @@ -84,11 +86,6 @@ def __init__( be used for service account credentials. """ - # Save the hostname. Default to port 443 (HTTPS) if none is specified. - if ":" not in host: - host += ":443" - self._host = host - scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES} # Save the scopes. @@ -109,6 +106,11 @@ def __init__( credentials, _ = google.auth.default( **scopes_kwargs, quota_project_id=quota_project_id ) + # Don't apply audience if the credentials file passed from user. + if hasattr(credentials, "with_gdch_audience"): + credentials = credentials.with_gdch_audience( + api_audience if api_audience else host + ) # If the credentials are service account credentials, then always try to use self signed JWT. if ( @@ -121,6 +123,11 @@ def __init__( # Save the credentials. self._credentials = credentials + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { @@ -154,6 +161,21 @@ def _prep_wrapped_messages(self, client_info): default_timeout=60.0, client_info=client_info, ), + self.run_aggregation_query: gapic_v1.method.wrap_method( + self.run_aggregation_query, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), self.begin_transaction: gapic_v1.method.wrap_method( self.begin_transaction, default_timeout=60.0, @@ -218,6 +240,18 @@ def run_query( ]: raise NotImplementedError() + @property + def run_aggregation_query( + self, + ) -> Callable[ + [datastore.RunAggregationQueryRequest], + Union[ + datastore.RunAggregationQueryResponse, + Awaitable[datastore.RunAggregationQueryResponse], + ], + ]: + raise NotImplementedError() + @property def begin_transaction( self, @@ -266,6 +300,39 @@ def reserve_ids( ]: raise NotImplementedError() + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], + Union[ + operations_pb2.ListOperationsResponse, + Awaitable[operations_pb2.ListOperationsResponse], + ], + ]: + raise NotImplementedError() + + @property + def get_operation( + self, + ) -> Callable[ + [operations_pb2.GetOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def cancel_operation( + self, + ) -> Callable[[operations_pb2.CancelOperationRequest], None,]: + raise NotImplementedError() + + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None,]: + raise NotImplementedError() + @property def kind(self) -> str: raise NotImplementedError() diff --git a/google/cloud/datastore_v1/services/datastore/transports/grpc.py b/google/cloud/datastore_v1/services/datastore/transports/grpc.py index 16938b68..4f160c45 100644 --- a/google/cloud/datastore_v1/services/datastore/transports/grpc.py +++ b/google/cloud/datastore_v1/services/datastore/transports/grpc.py @@ -25,6 +25,7 @@ import grpc # type: ignore from google.cloud.datastore_v1.types import datastore +from google.longrunning import operations_pb2 from .base import DatastoreTransport, DEFAULT_CLIENT_INFO @@ -64,6 +65,7 @@ def __init__( quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, ) -> None: """Instantiate the transport. @@ -159,6 +161,7 @@ def __init__( quota_project_id=quota_project_id, client_info=client_info, always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, ) if not self._grpc_channel: @@ -283,6 +286,34 @@ def run_query( ) return self._stubs["run_query"] + @property + def run_aggregation_query( + self, + ) -> Callable[ + [datastore.RunAggregationQueryRequest], datastore.RunAggregationQueryResponse + ]: + r"""Return a callable for the run aggregation query method over gRPC. + + Runs an aggregation query. + + Returns: + Callable[[~.RunAggregationQueryRequest], + ~.RunAggregationQueryResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "run_aggregation_query" not in self._stubs: + self._stubs["run_aggregation_query"] = self.grpc_channel.unary_unary( + "/google.datastore.v1.Datastore/RunAggregationQuery", + request_serializer=datastore.RunAggregationQueryRequest.serialize, + response_deserializer=datastore.RunAggregationQueryResponse.deserialize, + ) + return self._stubs["run_aggregation_query"] + @property def begin_transaction( self, @@ -419,6 +450,76 @@ def reserve_ids( def close(self): self.grpc_channel.close() + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def cancel_operation( + self, + ) -> Callable[[operations_pb2.CancelOperationRequest], None]: + r"""Return a callable for the cancel_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "cancel_operation" not in self._stubs: + self._stubs["cancel_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/CancelOperation", + request_serializer=operations_pb2.CancelOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["cancel_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + @property def kind(self) -> str: return "grpc" diff --git a/google/cloud/datastore_v1/services/datastore/transports/grpc_asyncio.py b/google/cloud/datastore_v1/services/datastore/transports/grpc_asyncio.py index f539e84f..529c2206 100644 --- a/google/cloud/datastore_v1/services/datastore/transports/grpc_asyncio.py +++ b/google/cloud/datastore_v1/services/datastore/transports/grpc_asyncio.py @@ -25,6 +25,7 @@ from grpc.experimental import aio # type: ignore from google.cloud.datastore_v1.types import datastore +from google.longrunning import operations_pb2 from .base import DatastoreTransport, DEFAULT_CLIENT_INFO from .grpc import DatastoreGrpcTransport @@ -109,6 +110,7 @@ def __init__( quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, ) -> None: """Instantiate the transport. @@ -204,6 +206,7 @@ def __init__( quota_project_id=quota_project_id, client_info=client_info, always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, ) if not self._grpc_channel: @@ -288,6 +291,35 @@ def run_query( ) return self._stubs["run_query"] + @property + def run_aggregation_query( + self, + ) -> Callable[ + [datastore.RunAggregationQueryRequest], + Awaitable[datastore.RunAggregationQueryResponse], + ]: + r"""Return a callable for the run aggregation query method over gRPC. + + Runs an aggregation query. + + Returns: + Callable[[~.RunAggregationQueryRequest], + Awaitable[~.RunAggregationQueryResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "run_aggregation_query" not in self._stubs: + self._stubs["run_aggregation_query"] = self.grpc_channel.unary_unary( + "/google.datastore.v1.Datastore/RunAggregationQuery", + request_serializer=datastore.RunAggregationQueryRequest.serialize, + response_deserializer=datastore.RunAggregationQueryResponse.deserialize, + ) + return self._stubs["run_aggregation_query"] + @property def begin_transaction( self, @@ -431,5 +463,75 @@ def reserve_ids( def close(self): return self.grpc_channel.close() + @property + def delete_operation( + self, + ) -> Callable[[operations_pb2.DeleteOperationRequest], None]: + r"""Return a callable for the delete_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_operation" not in self._stubs: + self._stubs["delete_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/DeleteOperation", + request_serializer=operations_pb2.DeleteOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["delete_operation"] + + @property + def cancel_operation( + self, + ) -> Callable[[operations_pb2.CancelOperationRequest], None]: + r"""Return a callable for the cancel_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "cancel_operation" not in self._stubs: + self._stubs["cancel_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/CancelOperation", + request_serializer=operations_pb2.CancelOperationRequest.SerializeToString, + response_deserializer=None, + ) + return self._stubs["cancel_operation"] + + @property + def get_operation( + self, + ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: + r"""Return a callable for the get_operation method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_operation" not in self._stubs: + self._stubs["get_operation"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/GetOperation", + request_serializer=operations_pb2.GetOperationRequest.SerializeToString, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["get_operation"] + + @property + def list_operations( + self, + ) -> Callable[ + [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse + ]: + r"""Return a callable for the list_operations method over gRPC.""" + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_operations" not in self._stubs: + self._stubs["list_operations"] = self.grpc_channel.unary_unary( + "/google.longrunning.Operations/ListOperations", + request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, + response_deserializer=operations_pb2.ListOperationsResponse.FromString, + ) + return self._stubs["list_operations"] + __all__ = ("DatastoreGrpcAsyncIOTransport",) diff --git a/google/cloud/datastore_v1/types/__init__.py b/google/cloud/datastore_v1/types/__init__.py index eb4fc8c2..ca7dae21 100644 --- a/google/cloud/datastore_v1/types/__init__.py +++ b/google/cloud/datastore_v1/types/__init__.py @@ -13,6 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from .aggregation_result import ( + AggregationResult, + AggregationResultBatch, +) from .datastore import ( AllocateIdsRequest, AllocateIdsResponse, @@ -29,6 +33,8 @@ ReserveIdsResponse, RollbackRequest, RollbackResponse, + RunAggregationQueryRequest, + RunAggregationQueryResponse, RunQueryRequest, RunQueryResponse, TransactionOptions, @@ -41,6 +47,7 @@ Value, ) from .query import ( + AggregationQuery, CompositeFilter, EntityResult, Filter, @@ -56,6 +63,8 @@ ) __all__ = ( + "AggregationResult", + "AggregationResultBatch", "AllocateIdsRequest", "AllocateIdsResponse", "BeginTransactionRequest", @@ -71,6 +80,8 @@ "ReserveIdsResponse", "RollbackRequest", "RollbackResponse", + "RunAggregationQueryRequest", + "RunAggregationQueryResponse", "RunQueryRequest", "RunQueryResponse", "TransactionOptions", @@ -79,6 +90,7 @@ "Key", "PartitionId", "Value", + "AggregationQuery", "CompositeFilter", "EntityResult", "Filter", diff --git a/google/cloud/datastore_v1/types/aggregation_result.py b/google/cloud/datastore_v1/types/aggregation_result.py new file mode 100644 index 00000000..17020a63 --- /dev/null +++ b/google/cloud/datastore_v1/types/aggregation_result.py @@ -0,0 +1,96 @@ +# -*- 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 proto # type: ignore + +from google.cloud.datastore_v1.types import entity +from google.cloud.datastore_v1.types import query +from google.protobuf import timestamp_pb2 # type: ignore + + +__protobuf__ = proto.module( + package="google.datastore.v1", + manifest={ + "AggregationResult", + "AggregationResultBatch", + }, +) + + +class AggregationResult(proto.Message): + r"""The result of a single bucket from a Datastore aggregation query. + + The keys of ``aggregate_properties`` are the same for all results in + an aggregation query, unlike entity queries which can have different + fields present for each result. + + Attributes: + aggregate_properties (Mapping[str, google.cloud.datastore_v1.types.Value]): + The result of the aggregation functions, ex: + ``COUNT(*) AS total_entities``. + + The key is the + [alias][google.datastore.v1.AggregationQuery.Aggregation.alias] + assigned to the aggregation function on input and the size + of this map equals the number of aggregation functions in + the query. + """ + + aggregate_properties = proto.MapField( + proto.STRING, + proto.MESSAGE, + number=2, + message=entity.Value, + ) + + +class AggregationResultBatch(proto.Message): + r"""A batch of aggregation results produced by an aggregation + query. + + Attributes: + aggregation_results (Sequence[google.cloud.datastore_v1.types.AggregationResult]): + The aggregation results for this batch. + more_results (google.cloud.datastore_v1.types.QueryResultBatch.MoreResultsType): + The state of the query after the current batch. Only + COUNT(*) aggregations are supported in the initial launch. + Therefore, expected result type is limited to + ``NO_MORE_RESULTS``. + read_time (google.protobuf.timestamp_pb2.Timestamp): + Read timestamp this batch was returned from. + In a single transaction, subsequent query result + batches for the same query can have a greater + timestamp. Each batch's read timestamp is valid + for all preceding batches. + """ + + aggregation_results = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="AggregationResult", + ) + more_results = proto.Field( + proto.ENUM, + number=2, + enum=query.QueryResultBatch.MoreResultsType, + ) + read_time = proto.Field( + proto.MESSAGE, + number=3, + message=timestamp_pb2.Timestamp, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/datastore_v1/types/datastore.py b/google/cloud/datastore_v1/types/datastore.py index f4907298..42c87f72 100644 --- a/google/cloud/datastore_v1/types/datastore.py +++ b/google/cloud/datastore_v1/types/datastore.py @@ -15,6 +15,7 @@ # import proto # type: ignore +from google.cloud.datastore_v1.types import aggregation_result from google.cloud.datastore_v1.types import entity from google.cloud.datastore_v1.types import query as gd_query from google.protobuf import timestamp_pb2 # type: ignore @@ -27,6 +28,8 @@ "LookupResponse", "RunQueryRequest", "RunQueryResponse", + "RunAggregationQueryRequest", + "RunAggregationQueryResponse", "BeginTransactionRequest", "BeginTransactionResponse", "RollbackRequest", @@ -53,6 +56,11 @@ class LookupRequest(proto.Message): project_id (str): Required. The ID of the project against which to make the request. + database_id (str): + The ID of the database against which to make + the request. + '(default)' is not allowed; please use empty + string '' to refer the default database. read_options (google.cloud.datastore_v1.types.ReadOptions): The options for this lookup request. keys (Sequence[google.cloud.datastore_v1.types.Key]): @@ -63,6 +71,10 @@ class LookupRequest(proto.Message): proto.STRING, number=8, ) + database_id = proto.Field( + proto.STRING, + number=9, + ) read_options = proto.Field( proto.MESSAGE, number=1, @@ -135,6 +147,11 @@ class RunQueryRequest(proto.Message): project_id (str): Required. The ID of the project against which to make the request. + database_id (str): + The ID of the database against which to make + the request. + '(default)' is not allowed; please use empty + string '' to refer the default database. partition_id (google.cloud.datastore_v1.types.PartitionId): Entities are partitioned into subsets, identified by a partition ID. Queries are scoped @@ -148,7 +165,8 @@ class RunQueryRequest(proto.Message): This field is a member of `oneof`_ ``query_type``. gql_query (google.cloud.datastore_v1.types.GqlQuery): - The GQL query to run. + The GQL query to run. This query must be a + non-aggregation query. This field is a member of `oneof`_ ``query_type``. """ @@ -157,6 +175,10 @@ class RunQueryRequest(proto.Message): proto.STRING, number=8, ) + database_id = proto.Field( + proto.STRING, + number=9, + ) partition_id = proto.Field( proto.MESSAGE, number=2, @@ -205,6 +227,102 @@ class RunQueryResponse(proto.Message): ) +class RunAggregationQueryRequest(proto.Message): + r"""The request for + [Datastore.RunAggregationQuery][google.datastore.v1.Datastore.RunAggregationQuery]. + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + project_id (str): + Required. The ID of the project against which + to make the request. + database_id (str): + The ID of the database against which to make + the request. + '(default)' is not allowed; please use empty + string '' to refer the default database. + partition_id (google.cloud.datastore_v1.types.PartitionId): + Entities are partitioned into subsets, + identified by a partition ID. Queries are scoped + to a single partition. This partition ID is + normalized with the standard default context + partition ID. + read_options (google.cloud.datastore_v1.types.ReadOptions): + The options for this query. + aggregation_query (google.cloud.datastore_v1.types.AggregationQuery): + The query to run. + + This field is a member of `oneof`_ ``query_type``. + gql_query (google.cloud.datastore_v1.types.GqlQuery): + The GQL query to run. This query must be an + aggregation query. + + This field is a member of `oneof`_ ``query_type``. + """ + + project_id = proto.Field( + proto.STRING, + number=8, + ) + database_id = proto.Field( + proto.STRING, + number=9, + ) + partition_id = proto.Field( + proto.MESSAGE, + number=2, + message=entity.PartitionId, + ) + read_options = proto.Field( + proto.MESSAGE, + number=1, + message="ReadOptions", + ) + aggregation_query = proto.Field( + proto.MESSAGE, + number=3, + oneof="query_type", + message=gd_query.AggregationQuery, + ) + gql_query = proto.Field( + proto.MESSAGE, + number=7, + oneof="query_type", + message=gd_query.GqlQuery, + ) + + +class RunAggregationQueryResponse(proto.Message): + r"""The response for + [Datastore.RunAggregationQuery][google.datastore.v1.Datastore.RunAggregationQuery]. + + Attributes: + batch (google.cloud.datastore_v1.types.AggregationResultBatch): + A batch of aggregation results. Always + present. + query (google.cloud.datastore_v1.types.AggregationQuery): + The parsed form of the ``GqlQuery`` from the request, if it + was set. + """ + + batch = proto.Field( + proto.MESSAGE, + number=1, + message=aggregation_result.AggregationResultBatch, + ) + query = proto.Field( + proto.MESSAGE, + number=2, + message=gd_query.AggregationQuery, + ) + + class BeginTransactionRequest(proto.Message): r"""The request for [Datastore.BeginTransaction][google.datastore.v1.Datastore.BeginTransaction]. @@ -213,6 +331,11 @@ class BeginTransactionRequest(proto.Message): project_id (str): Required. The ID of the project against which to make the request. + database_id (str): + The ID of the database against which to make + the request. + '(default)' is not allowed; please use empty + string '' to refer the default database. transaction_options (google.cloud.datastore_v1.types.TransactionOptions): Options for a new transaction. """ @@ -221,6 +344,10 @@ class BeginTransactionRequest(proto.Message): proto.STRING, number=8, ) + database_id = proto.Field( + proto.STRING, + number=9, + ) transaction_options = proto.Field( proto.MESSAGE, number=10, @@ -251,6 +378,11 @@ class RollbackRequest(proto.Message): project_id (str): Required. The ID of the project against which to make the request. + database_id (str): + The ID of the database against which to make + the request. + '(default)' is not allowed; please use empty + string '' to refer the default database. transaction (bytes): Required. The transaction identifier, returned by a call to [Datastore.BeginTransaction][google.datastore.v1.Datastore.BeginTransaction]. @@ -260,6 +392,10 @@ class RollbackRequest(proto.Message): proto.STRING, number=8, ) + database_id = proto.Field( + proto.STRING, + number=9, + ) transaction = proto.Field( proto.BYTES, number=1, @@ -285,6 +421,11 @@ class CommitRequest(proto.Message): project_id (str): Required. The ID of the project against which to make the request. + database_id (str): + The ID of the database against which to make + the request. + '(default)' is not allowed; please use empty + string '' to refer the default database. mode (google.cloud.datastore_v1.types.CommitRequest.Mode): The type of commit to perform. Defaults to ``TRANSACTIONAL``. @@ -321,6 +462,10 @@ class Mode(proto.Enum): proto.STRING, number=8, ) + database_id = proto.Field( + proto.STRING, + number=9, + ) mode = proto.Field( proto.ENUM, number=5, @@ -379,6 +524,11 @@ class AllocateIdsRequest(proto.Message): project_id (str): Required. The ID of the project against which to make the request. + database_id (str): + The ID of the database against which to make + the request. + '(default)' is not allowed; please use empty + string '' to refer the default database. keys (Sequence[google.cloud.datastore_v1.types.Key]): Required. A list of keys with incomplete key paths for which to allocate IDs. No key may be @@ -389,6 +539,10 @@ class AllocateIdsRequest(proto.Message): proto.STRING, number=8, ) + database_id = proto.Field( + proto.STRING, + number=9, + ) keys = proto.RepeatedField( proto.MESSAGE, number=1, @@ -423,8 +577,10 @@ class ReserveIdsRequest(proto.Message): Required. The ID of the project against which to make the request. database_id (str): - If not empty, the ID of the database against - which to make the request. + The ID of the database against which to make + the request. + '(default)' is not allowed; please use empty + string '' to refer the default database. keys (Sequence[google.cloud.datastore_v1.types.Key]): Required. A list of keys with complete key paths whose numeric IDs should not be @@ -602,8 +758,8 @@ class ReadOptions(proto.Message): Attributes: read_consistency (google.cloud.datastore_v1.types.ReadOptions.ReadConsistency): - The non-transactional read consistency to use. Cannot be set - to ``STRONG`` for global queries. + The non-transactional read consistency to + use. This field is a member of `oneof`_ ``consistency_type``. transaction (bytes): diff --git a/google/cloud/datastore_v1/types/entity.py b/google/cloud/datastore_v1/types/entity.py index e949a56a..d9b8febe 100644 --- a/google/cloud/datastore_v1/types/entity.py +++ b/google/cloud/datastore_v1/types/entity.py @@ -57,6 +57,9 @@ class PartitionId(proto.Message): project_id (str): The ID of the project to which the entities belong. + database_id (str): + If not empty, the ID of the database to which + the entities belong. namespace_id (str): If not empty, the ID of the namespace to which the entities belong. @@ -66,6 +69,10 @@ class PartitionId(proto.Message): proto.STRING, number=2, ) + database_id = proto.Field( + proto.STRING, + number=3, + ) namespace_id = proto.Field( proto.STRING, number=4, @@ -121,9 +128,15 @@ class PathElement(proto.Message): Attributes: kind (str): - The kind of the entity. A kind matching regex ``__.*__`` is - reserved/read-only. A kind must not contain more than 1500 - bytes when UTF-8 encoded. Cannot be ``""``. + The kind of the entity. + + A kind matching regex ``__.*__`` is reserved/read-only. A + kind must not contain more than 1500 bytes when UTF-8 + encoded. Cannot be ``""``. + + Must be valid UTF-8 bytes. Legacy values that are not valid + UTF-8 are encoded as ``__bytes__`` where ```` is the + base-64 encoding of the bytes. id (int): The auto-allocated ID of the entity. Never equal to zero. Values less than zero are @@ -132,9 +145,15 @@ class PathElement(proto.Message): This field is a member of `oneof`_ ``id_type``. name (str): - The name of the entity. A name matching regex ``__.*__`` is - reserved/read-only. A name must not be more than 1500 bytes - when UTF-8 encoded. Cannot be ``""``. + The name of the entity. + + A name matching regex ``__.*__`` is reserved/read-only. A + name must not be more than 1500 bytes when UTF-8 encoded. + Cannot be ``""``. + + Must be valid UTF-8 bytes. Legacy values that are not valid + UTF-8 are encoded as ``__bytes__`` where ```` is the + base-64 encoding of the bytes. This field is a member of `oneof`_ ``id_type``. """ diff --git a/google/cloud/datastore_v1/types/query.py b/google/cloud/datastore_v1/types/query.py index 1179efce..a3f6b75d 100644 --- a/google/cloud/datastore_v1/types/query.py +++ b/google/cloud/datastore_v1/types/query.py @@ -25,6 +25,7 @@ manifest={ "EntityResult", "Query", + "AggregationQuery", "KindExpression", "PropertyReference", "Projection", @@ -188,6 +189,137 @@ class Query(proto.Message): ) +class AggregationQuery(proto.Message): + r"""Datastore query for running an aggregation over a + [Query][google.datastore.v1.Query]. + + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + nested_query (google.cloud.datastore_v1.types.Query): + Nested query for aggregation + + This field is a member of `oneof`_ ``query_type``. + aggregations (Sequence[google.cloud.datastore_v1.types.AggregationQuery.Aggregation]): + Optional. Series of aggregations to apply over the results + of the ``nested_query``. + + Requires: + + - A minimum of one and maximum of five aggregations per + query. + """ + + class Aggregation(proto.Message): + r"""Defines a aggregation that produces a single result. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + count (google.cloud.datastore_v1.types.AggregationQuery.Aggregation.Count): + Count aggregator. + + This field is a member of `oneof`_ ``operator``. + alias (str): + Optional. Optional name of the property to store the result + of the aggregation. + + If not provided, Datastore will pick a default name + following the format ``property_``. For + example: + + :: + + AGGREGATE + COUNT_UP_TO(1) AS count_up_to_1, + COUNT_UP_TO(2), + COUNT_UP_TO(3) AS count_up_to_3, + COUNT_UP_TO(4) + OVER ( + ... + ); + + becomes: + + :: + + AGGREGATE + COUNT_UP_TO(1) AS count_up_to_1, + COUNT_UP_TO(2) AS property_1, + COUNT_UP_TO(3) AS count_up_to_3, + COUNT_UP_TO(4) AS property_2 + OVER ( + ... + ); + + Requires: + + - Must be unique across all aggregation aliases. + - Conform to [entity property + name][google.datastore.v1.Entity.properties] limitations. + """ + + class Count(proto.Message): + r"""Count of entities that match the query. + + The ``COUNT(*)`` aggregation function operates on the entire entity + so it does not require a field reference. + + Attributes: + up_to (google.protobuf.wrappers_pb2.Int64Value): + Optional. Optional constraint on the maximum number of + entities to count. + + This provides a way to set an upper bound on the number of + entities to scan, limiting latency and cost. + + Unspecified is interpreted as no bound. + + If a zero value is provided, a count result of zero should + always be expected. + + High-Level Example: + + :: + + AGGREGATE COUNT_UP_TO(1000) OVER ( SELECT * FROM k ); + + Requires: + + - Must be non-negative when present. + """ + + up_to = proto.Field( + proto.MESSAGE, + number=1, + message=wrappers_pb2.Int64Value, + ) + + count = proto.Field( + proto.MESSAGE, + number=1, + oneof="operator", + message="AggregationQuery.Aggregation.Count", + ) + alias = proto.Field( + proto.STRING, + number=7, + ) + + nested_query = proto.Field( + proto.MESSAGE, + number=1, + oneof="query_type", + message="Query", + ) + aggregations = proto.RepeatedField( + proto.MESSAGE, + number=3, + message=Aggregation, + ) + + class KindExpression(proto.Message): r"""A representation of a kind. @@ -305,7 +437,10 @@ class CompositeFilter(proto.Message): The operator for combining multiple filters. filters (Sequence[google.cloud.datastore_v1.types.Filter]): The list of filters to combine. - Must contain at least one filter. + + Requires: + + - At least one filter is present. """ class Operator(proto.Enum): diff --git a/noxfile.py b/noxfile.py index 80ff3c44..cce65bdd 100644 --- a/noxfile.py +++ b/noxfile.py @@ -129,7 +129,7 @@ def mypy(session): session.install( "mypy", "types-setuptools", "types-mock", "types-protobuf", "types-requests" ) - session.run("mypy", "google/", "tests/") + session.run("mypy", "google/") @nox.session(python=DEFAULT_PYTHON_VERSION) diff --git a/owlbot.py b/owlbot.py index 40f95a22..530adcf2 100644 --- a/owlbot.py +++ b/owlbot.py @@ -279,7 +279,7 @@ def mypy(session): session.install( "mypy", "types-setuptools", "types-mock", "types-protobuf", "types-requests" ) - session.run("mypy", "google/", "tests/") + session.run("mypy", "google/") @nox.session(python=DEFAULT_PYTHON_VERSION) diff --git a/scripts/fixup_datastore_v1_keywords.py b/scripts/fixup_datastore_v1_keywords.py index 4f5265b6..82a24a4f 100644 --- a/scripts/fixup_datastore_v1_keywords.py +++ b/scripts/fixup_datastore_v1_keywords.py @@ -39,13 +39,14 @@ def partition( class datastoreCallTransformer(cst.CSTTransformer): CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { - 'allocate_ids': ('project_id', 'keys', ), - 'begin_transaction': ('project_id', 'transaction_options', ), - 'commit': ('project_id', 'mode', 'transaction', 'mutations', ), - 'lookup': ('project_id', 'keys', 'read_options', ), + 'allocate_ids': ('project_id', 'keys', 'database_id', ), + 'begin_transaction': ('project_id', 'database_id', 'transaction_options', ), + 'commit': ('project_id', 'database_id', 'mode', 'transaction', 'mutations', ), + 'lookup': ('project_id', 'keys', 'database_id', 'read_options', ), 'reserve_ids': ('project_id', 'keys', 'database_id', ), - 'rollback': ('project_id', 'transaction', ), - 'run_query': ('project_id', 'partition_id', 'read_options', 'query', 'gql_query', ), + 'rollback': ('project_id', 'transaction', 'database_id', ), + 'run_aggregation_query': ('project_id', 'database_id', 'partition_id', 'read_options', 'aggregation_query', 'gql_query', ), + 'run_query': ('project_id', 'database_id', 'partition_id', 'read_options', 'query', 'gql_query', ), } def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: diff --git a/setup.py b/setup.py index 4001b3e5..1de1269c 100644 --- a/setup.py +++ b/setup.py @@ -29,13 +29,7 @@ # 'Development Status :: 5 - Production/Stable' release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - # NOTE: Maintainers, please do not require google-api-core>=2.x.x - # Until this issue is closed - # https://github.com/googleapis/google-cloud-python/issues/10566 - "google-api-core[grpc] >= 1.31.5, <3.0.0dev,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0", - # NOTE: Maintainers, please do not require google-api-core>=2.x.x - # Until this issue is closed - # https://github.com/googleapis/google-cloud-python/issues/10566 + "google-api-core[grpc] >= 1.32.0, <3.0.0dev,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*", "google-cloud-core >= 1.4.0, <3.0.0dev", "proto-plus >= 1.22.0, <2.0.0dev", "protobuf >= 3.20.2, <5.0.0dev", diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt index 5b0708c7..868dedf2 100644 --- a/testing/constraints-3.7.txt +++ b/testing/constraints-3.7.txt @@ -5,7 +5,7 @@ # # e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", # Then this file should have foo==1.14.0 -google-api-core==1.31.5 +google-api-core==1.32.0 google-cloud-core==1.4.0 proto-plus==1.22.0 libcst==0.2.5 diff --git a/tests/unit/gapic/datastore_admin_v1/test_datastore_admin.py b/tests/unit/gapic/datastore_admin_v1/test_datastore_admin.py index fd1fc14c..13c26fa9 100644 --- a/tests/unit/gapic/datastore_admin_v1/test_datastore_admin.py +++ b/tests/unit/gapic/datastore_admin_v1/test_datastore_admin.py @@ -14,14 +14,20 @@ # limitations under the License. # import os -import mock + +# try/except added for compatibility with python < 3.8 +try: + from unittest import mock + from unittest.mock import AsyncMock # pragma: NO COVER +except ImportError: # pragma: NO COVER + import mock import grpc from grpc.experimental import aio import math import pytest from proto.marshal.rules.dates import DurationRule, TimestampRule - +from proto.marshal.rules import wrappers from google.api_core import client_options from google.api_core import exceptions as core_exceptions @@ -228,6 +234,7 @@ def test_datastore_admin_client_client_options( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is @@ -245,6 +252,7 @@ def test_datastore_admin_client_client_options( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is @@ -262,6 +270,7 @@ def test_datastore_admin_client_client_options( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has @@ -291,6 +300,25 @@ def test_datastore_admin_client_client_options( quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, + ) + # Check the case api_endpoint is provided + options = client_options.ClientOptions( + api_audience="https://language.googleapis.com" + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience="https://language.googleapis.com", ) @@ -358,6 +386,7 @@ def test_datastore_admin_client_mtls_env_auto( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # Check the case ADC client cert is provided. Whether client cert is used depends on @@ -392,6 +421,7 @@ def test_datastore_admin_client_mtls_env_auto( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # Check the case client_cert_source and ADC client cert are not provided. @@ -414,6 +444,7 @@ def test_datastore_admin_client_mtls_env_auto( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) @@ -528,6 +559,7 @@ def test_datastore_admin_client_client_options_scopes( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) @@ -566,6 +598,7 @@ def test_datastore_admin_client_client_options_credentials_file( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) @@ -586,6 +619,7 @@ def test_datastore_admin_client_client_options_from_dict(): quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) @@ -624,6 +658,7 @@ def test_datastore_admin_client_create_channel_credentials_file( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # test that the credentials from file are saved and used as the credentials. @@ -741,6 +776,67 @@ async def test_export_entities_async_from_dict(): await test_export_entities_async(request_type=dict) +def test_export_entities_field_headers(): + client = DatastoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.ExportEntitiesRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.export_entities), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.export_entities(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_export_entities_field_headers_async(): + client = DatastoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.ExportEntitiesRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.export_entities), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.export_entities(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + def test_export_entities_flattened(): client = DatastoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -936,6 +1032,67 @@ async def test_import_entities_async_from_dict(): await test_import_entities_async(request_type=dict) +def test_import_entities_field_headers(): + client = DatastoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.ImportEntitiesRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.import_entities), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.import_entities(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_import_entities_field_headers_async(): + client = DatastoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.ImportEntitiesRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.import_entities), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.import_entities(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + def test_import_entities_flattened(): client = DatastoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -1131,6 +1288,67 @@ async def test_create_index_async_from_dict(): await test_create_index_async(request_type=dict) +def test_create_index_field_headers(): + client = DatastoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.CreateIndexRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_index), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.create_index(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_create_index_field_headers_async(): + client = DatastoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.CreateIndexRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_index), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.create_index(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + @pytest.mark.parametrize( "request_type", [ @@ -1214,6 +1432,69 @@ async def test_delete_index_async_from_dict(): await test_delete_index_async(request_type=dict) +def test_delete_index_field_headers(): + client = DatastoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.DeleteIndexRequest() + + request.project_id = "project_id_value" + request.index_id = "index_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_index), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.delete_index(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value&index_id=index_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_index_field_headers_async(): + client = DatastoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.DeleteIndexRequest() + + request.project_id = "project_id_value" + request.index_id = "index_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_index), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.delete_index(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value&index_id=index_id_value", + ) in kw["metadata"] + + @pytest.mark.parametrize( "request_type", [ @@ -1319,6 +1600,67 @@ async def test_get_index_async_from_dict(): await test_get_index_async(request_type=dict) +def test_get_index_field_headers(): + client = DatastoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.GetIndexRequest() + + request.project_id = "project_id_value" + request.index_id = "index_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_index), "__call__") as call: + call.return_value = index.Index() + client.get_index(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value&index_id=index_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_index_field_headers_async(): + client = DatastoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.GetIndexRequest() + + request.project_id = "project_id_value" + request.index_id = "index_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_index), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(index.Index()) + await client.get_index(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value&index_id=index_id_value", + ) in kw["metadata"] + + @pytest.mark.parametrize( "request_type", [ @@ -1408,6 +1750,67 @@ async def test_list_indexes_async_from_dict(): await test_list_indexes_async(request_type=dict) +def test_list_indexes_field_headers(): + client = DatastoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.ListIndexesRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_indexes), "__call__") as call: + call.return_value = datastore_admin.ListIndexesResponse() + client.list_indexes(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_indexes_field_headers_async(): + client = DatastoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore_admin.ListIndexesRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_indexes), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + datastore_admin.ListIndexesResponse() + ) + await client.list_indexes(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + def test_list_indexes_pager(transport_name: str = "grpc"): client = DatastoreAdminClient( credentials=ga_credentials.AnonymousCredentials, @@ -1446,11 +1849,14 @@ def test_list_indexes_pager(transport_name: str = "grpc"): ) metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("project_id", ""),)), + ) pager = client.list_indexes(request={}) assert pager._metadata == metadata - results = [i for i in pager] + results = list(pager) assert len(results) == 6 assert all(isinstance(i, index.Index) for i in results) @@ -1831,6 +2237,28 @@ def test_datastore_admin_transport_auth_adc(transport_class): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.DatastoreAdminGrpcTransport, + transports.DatastoreAdminGrpcAsyncIOTransport, + ], +) +def test_datastore_admin_transport_auth_gdch_credentials(transport_class): + host = "https://language.com" + api_audience_tests = [None, "https://language2.com"] + api_audience_expect = [host, "https://language2.com"] + for t, e in zip(api_audience_tests, api_audience_expect): + with mock.patch.object(google.auth, "default", autospec=True) as adc: + gdch_mock = mock.MagicMock() + type(gdch_mock).with_gdch_audience = mock.PropertyMock( + return_value=gdch_mock + ) + adc.return_value = (gdch_mock, None) + transport_class(host=host, api_audience=t) + gdch_mock.with_gdch_audience.assert_called_once_with(e) + + @pytest.mark.parametrize( "transport_class,grpc_helpers", [ @@ -2310,4 +2738,5 @@ def test_api_key_credentials(client_class, transport_class): quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) diff --git a/tests/unit/gapic/datastore_v1/test_datastore.py b/tests/unit/gapic/datastore_v1/test_datastore.py index 4106b217..7448690a 100644 --- a/tests/unit/gapic/datastore_v1/test_datastore.py +++ b/tests/unit/gapic/datastore_v1/test_datastore.py @@ -14,14 +14,20 @@ # limitations under the License. # import os -import mock + +# try/except added for compatibility with python < 3.8 +try: + from unittest import mock + from unittest.mock import AsyncMock # pragma: NO COVER +except ImportError: # pragma: NO COVER + import mock import grpc from grpc.experimental import aio import math import pytest from proto.marshal.rules.dates import DurationRule, TimestampRule - +from proto.marshal.rules import wrappers from google.api_core import client_options from google.api_core import exceptions as core_exceptions @@ -34,9 +40,11 @@ from google.cloud.datastore_v1.services.datastore import DatastoreAsyncClient from google.cloud.datastore_v1.services.datastore import DatastoreClient from google.cloud.datastore_v1.services.datastore import transports +from google.cloud.datastore_v1.types import aggregation_result from google.cloud.datastore_v1.types import datastore from google.cloud.datastore_v1.types import entity from google.cloud.datastore_v1.types import query +from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import struct_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore @@ -214,6 +222,7 @@ def test_datastore_client_client_options(client_class, transport_class, transpor quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is @@ -231,6 +240,7 @@ def test_datastore_client_client_options(client_class, transport_class, transpor quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is @@ -248,6 +258,7 @@ def test_datastore_client_client_options(client_class, transport_class, transpor quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has @@ -277,6 +288,25 @@ def test_datastore_client_client_options(client_class, transport_class, transpor quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, + ) + # Check the case api_endpoint is provided + options = client_options.ClientOptions( + api_audience="https://language.googleapis.com" + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options, transport=transport_name) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + api_audience="https://language.googleapis.com", ) @@ -342,6 +372,7 @@ def test_datastore_client_mtls_env_auto( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # Check the case ADC client cert is provided. Whether client cert is used depends on @@ -376,6 +407,7 @@ def test_datastore_client_mtls_env_auto( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # Check the case client_cert_source and ADC client cert are not provided. @@ -398,6 +430,7 @@ def test_datastore_client_mtls_env_auto( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) @@ -508,6 +541,7 @@ def test_datastore_client_client_options_scopes( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) @@ -541,6 +575,7 @@ def test_datastore_client_client_options_credentials_file( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) @@ -559,6 +594,7 @@ def test_datastore_client_client_options_from_dict(): quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) @@ -592,6 +628,7 @@ def test_datastore_client_create_channel_credentials_file( quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, ) # test that the credentials from file are saved and used as the credentials. @@ -709,6 +746,67 @@ async def test_lookup_async_from_dict(): await test_lookup_async(request_type=dict) +def test_lookup_field_headers(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.LookupRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.lookup), "__call__") as call: + call.return_value = datastore.LookupResponse() + client.lookup(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_lookup_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.LookupRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.lookup), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + datastore.LookupResponse() + ) + await client.lookup(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + def test_lookup_flattened(): client = DatastoreClient( credentials=ga_credentials.AnonymousCredentials(), @@ -926,6 +1024,221 @@ async def test_run_query_async_from_dict(): await test_run_query_async(request_type=dict) +def test_run_query_field_headers(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.RunQueryRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_query), "__call__") as call: + call.return_value = datastore.RunQueryResponse() + client.run_query(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_run_query_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.RunQueryRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_query), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + datastore.RunQueryResponse() + ) + await client.run_query(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.parametrize( + "request_type", + [ + datastore.RunAggregationQueryRequest, + dict, + ], +) +def test_run_aggregation_query(request_type, transport: str = "grpc"): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.run_aggregation_query), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = datastore.RunAggregationQueryResponse() + response = client.run_aggregation_query(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == datastore.RunAggregationQueryRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, datastore.RunAggregationQueryResponse) + + +def test_run_aggregation_query_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.run_aggregation_query), "__call__" + ) as call: + client.run_aggregation_query() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == datastore.RunAggregationQueryRequest() + + +@pytest.mark.asyncio +async def test_run_aggregation_query_async( + transport: str = "grpc_asyncio", request_type=datastore.RunAggregationQueryRequest +): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.run_aggregation_query), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + datastore.RunAggregationQueryResponse() + ) + response = await client.run_aggregation_query(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == datastore.RunAggregationQueryRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, datastore.RunAggregationQueryResponse) + + +@pytest.mark.asyncio +async def test_run_aggregation_query_async_from_dict(): + await test_run_aggregation_query_async(request_type=dict) + + +def test_run_aggregation_query_field_headers(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.RunAggregationQueryRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.run_aggregation_query), "__call__" + ) as call: + call.return_value = datastore.RunAggregationQueryResponse() + client.run_aggregation_query(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_run_aggregation_query_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.RunAggregationQueryRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.run_aggregation_query), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + datastore.RunAggregationQueryResponse() + ) + await client.run_aggregation_query(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + @pytest.mark.parametrize( "request_type", [ @@ -1021,6 +1334,71 @@ async def test_begin_transaction_async_from_dict(): await test_begin_transaction_async(request_type=dict) +def test_begin_transaction_field_headers(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.BeginTransactionRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.begin_transaction), "__call__" + ) as call: + call.return_value = datastore.BeginTransactionResponse() + client.begin_transaction(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_begin_transaction_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.BeginTransactionRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.begin_transaction), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + datastore.BeginTransactionResponse() + ) + await client.begin_transaction(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + def test_begin_transaction_flattened(): client = DatastoreClient( credentials=ga_credentials.AnonymousCredentials(), @@ -1196,29 +1574,90 @@ async def test_commit_async_from_dict(): await test_commit_async(request_type=dict) -def test_commit_flattened(): +def test_commit_field_headers(): client = DatastoreClient( credentials=ga_credentials.AnonymousCredentials(), ) + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.CommitRequest() + + request.project_id = "project_id_value" + # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.commit), "__call__") as call: - # Designate an appropriate return value for the call. call.return_value = datastore.CommitResponse() - # Call the method with a truthy value for each flattened field, - # using the keyword arguments to the method. - client.commit( - project_id="project_id_value", - mode=datastore.CommitRequest.Mode.TRANSACTIONAL, - transaction=b"transaction_blob", - mutations=[ - datastore.Mutation( - insert=entity.Entity( - key=entity.Key( - partition_id=entity.PartitionId( - project_id="project_id_value" - ) - ) + client.commit(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_commit_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.CommitRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.commit), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + datastore.CommitResponse() + ) + await client.commit(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +def test_commit_flattened(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.commit), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = datastore.CommitResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.commit( + project_id="project_id_value", + mode=datastore.CommitRequest.Mode.TRANSACTIONAL, + transaction=b"transaction_blob", + mutations=[ + datastore.Mutation( + insert=entity.Entity( + key=entity.Key( + partition_id=entity.PartitionId( + project_id="project_id_value" + ) + ) ) ) ], @@ -1443,6 +1882,67 @@ async def test_rollback_async_from_dict(): await test_rollback_async(request_type=dict) +def test_rollback_field_headers(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.RollbackRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.rollback), "__call__") as call: + call.return_value = datastore.RollbackResponse() + client.rollback(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_rollback_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.RollbackRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.rollback), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + datastore.RollbackResponse() + ) + await client.rollback(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + def test_rollback_flattened(): client = DatastoreClient( credentials=ga_credentials.AnonymousCredentials(), @@ -1618,6 +2118,67 @@ async def test_allocate_ids_async_from_dict(): await test_allocate_ids_async(request_type=dict) +def test_allocate_ids_field_headers(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.AllocateIdsRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.allocate_ids), "__call__") as call: + call.return_value = datastore.AllocateIdsResponse() + client.allocate_ids(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_allocate_ids_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.AllocateIdsRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.allocate_ids), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + datastore.AllocateIdsResponse() + ) + await client.allocate_ids(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + def test_allocate_ids_flattened(): client = DatastoreClient( credentials=ga_credentials.AnonymousCredentials(), @@ -1813,6 +2374,67 @@ async def test_reserve_ids_async_from_dict(): await test_reserve_ids_async(request_type=dict) +def test_reserve_ids_field_headers(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.ReserveIdsRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.reserve_ids), "__call__") as call: + call.return_value = datastore.ReserveIdsResponse() + client.reserve_ids(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_reserve_ids_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = datastore.ReserveIdsRequest() + + request.project_id = "project_id_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.reserve_ids), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + datastore.ReserveIdsResponse() + ) + await client.reserve_ids(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "project_id=project_id_value", + ) in kw["metadata"] + + def test_reserve_ids_flattened(): client = DatastoreClient( credentials=ga_credentials.AnonymousCredentials(), @@ -2064,11 +2686,16 @@ def test_datastore_base_transport(): methods = ( "lookup", "run_query", + "run_aggregation_query", "begin_transaction", "commit", "rollback", "allocate_ids", "reserve_ids", + "get_operation", + "cancel_operation", + "delete_operation", + "list_operations", ) for method in methods: with pytest.raises(NotImplementedError): @@ -2159,6 +2786,28 @@ def test_datastore_transport_auth_adc(transport_class): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.DatastoreGrpcTransport, + transports.DatastoreGrpcAsyncIOTransport, + ], +) +def test_datastore_transport_auth_gdch_credentials(transport_class): + host = "https://language.com" + api_audience_tests = [None, "https://language2.com"] + api_audience_expect = [host, "https://language2.com"] + for t, e in zip(api_audience_tests, api_audience_expect): + with mock.patch.object(google.auth, "default", autospec=True) as adc: + gdch_mock = mock.MagicMock() + type(gdch_mock).with_gdch_audience = mock.PropertyMock( + return_value=gdch_mock + ) + adc.return_value = (gdch_mock, None) + transport_class(host=host, api_audience=t) + gdch_mock.with_gdch_audience.assert_called_once_with(e) + + @pytest.mark.parametrize( "transport_class,grpc_helpers", [ @@ -2533,6 +3182,574 @@ async def test_transport_close_async(): close.assert_called_once() +def test_delete_operation(transport: str = "grpc"): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_delete_operation_async(transport: str = "grpc"): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.DeleteOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_operation_field_headers(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = None + + client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_operation_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.DeleteOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_delete_operation_from_dict(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + + response = client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_delete_operation_from_dict_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_cancel_operation(transport: str = "grpc"): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.CancelOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.cancel_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.cancel_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_cancel_operation_async(transport: str = "grpc"): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.CancelOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.cancel_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.cancel_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +def test_cancel_operation_field_headers(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.CancelOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.cancel_operation), "__call__") as call: + call.return_value = None + + client.cancel_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_cancel_operation_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.CancelOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.cancel_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.cancel_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_cancel_operation_from_dict(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.cancel_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + + response = client.cancel_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_cancel_operation_from_dict_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.cancel_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.cancel_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_get_operation(transport: str = "grpc"): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + response = client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +@pytest.mark.asyncio +async def test_get_operation_async(transport: str = "grpc"): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.GetOperationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.Operation) + + +def test_get_operation_field_headers(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = operations_pb2.Operation() + + client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_operation_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.GetOperationRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + await client.get_operation(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_get_operation_from_dict(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation() + + response = client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_get_operation_from_dict_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_operation), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation() + ) + response = await client.get_operation( + request={ + "name": "locations", + } + ) + call.assert_called() + + +def test_list_operations(transport: str = "grpc"): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + response = client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +@pytest.mark.asyncio +async def test_list_operations_async(transport: str = "grpc"): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = operations_pb2.ListOperationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, operations_pb2.ListOperationsResponse) + + +def test_list_operations_field_headers(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = operations_pb2.ListOperationsResponse() + + client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_operations_field_headers_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = operations_pb2.ListOperationsRequest() + request.name = "locations" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + await client.list_operations(request) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=locations", + ) in kw["metadata"] + + +def test_list_operations_from_dict(): + client = DatastoreClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.ListOperationsResponse() + + response = client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + +@pytest.mark.asyncio +async def test_list_operations_from_dict_async(): + client = DatastoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_operations), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.ListOperationsResponse() + ) + response = await client.list_operations( + request={ + "name": "locations", + } + ) + call.assert_called() + + def test_transport_close(): transports = { "grpc": "_grpc_channel", @@ -2593,4 +3810,5 @@ def test_api_key_credentials(client_class, transport_class): quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, always_use_jwt_access=True, + api_audience=None, )