1# -*- coding: utf-8 -*- 
    2# Copyright 2025 Google LLC 
    3# 
    4# Licensed under the Apache License, Version 2.0 (the "License"); 
    5# you may not use this file except in compliance with the License. 
    6# You may obtain a copy of the License at 
    7# 
    8#     http://www.apache.org/licenses/LICENSE-2.0 
    9# 
    10# Unless required by applicable law or agreed to in writing, software 
    11# distributed under the License is distributed on an "AS IS" BASIS, 
    12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    13# See the License for the specific language governing permissions and 
    14# limitations under the License. 
    15# 
    16import inspect 
    17import json 
    18import pickle 
    19import logging as std_logging 
    20import warnings 
    21from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union 
    22 
    23from google.api_core import gapic_v1 
    24from google.api_core import grpc_helpers_async 
    25from google.api_core import exceptions as core_exceptions 
    26from google.api_core import retry_async as retries 
    27from google.auth import credentials as ga_credentials  # type: ignore 
    28from google.auth.transport.grpc import SslCredentials  # type: ignore 
    29from google.protobuf.json_format import MessageToJson 
    30import google.protobuf.message 
    31 
    32import grpc  # type: ignore 
    33import proto  # type: ignore 
    34from grpc.experimental import aio  # type: ignore 
    35 
    36from google.cloud.logging_v2.types import logging_metrics 
    37from google.longrunning import operations_pb2  # type: ignore 
    38from google.protobuf import empty_pb2  # type: ignore 
    39from .base import MetricsServiceV2Transport, DEFAULT_CLIENT_INFO 
    40from .grpc import MetricsServiceV2GrpcTransport 
    41 
    42try: 
    43    from google.api_core import client_logging  # type: ignore 
    44 
    45    CLIENT_LOGGING_SUPPORTED = True  # pragma: NO COVER 
    46except ImportError:  # pragma: NO COVER 
    47    CLIENT_LOGGING_SUPPORTED = False 
    48 
    49_LOGGER = std_logging.getLogger(__name__) 
    50 
    51 
    52class _LoggingClientAIOInterceptor( 
    53    grpc.aio.UnaryUnaryClientInterceptor 
    54):  # pragma: NO COVER 
    55    async def intercept_unary_unary(self, continuation, client_call_details, request): 
    56        logging_enabled = CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( 
    57            std_logging.DEBUG 
    58        ) 
    59        if logging_enabled:  # pragma: NO COVER 
    60            request_metadata = client_call_details.metadata 
    61            if isinstance(request, proto.Message): 
    62                request_payload = type(request).to_json(request) 
    63            elif isinstance(request, google.protobuf.message.Message): 
    64                request_payload = MessageToJson(request) 
    65            else: 
    66                request_payload = f"{type(request).__name__}: {pickle.dumps(request)}" 
    67 
    68            request_metadata = { 
    69                key: value.decode("utf-8") if isinstance(value, bytes) else value 
    70                for key, value in request_metadata 
    71            } 
    72            grpc_request = { 
    73                "payload": request_payload, 
    74                "requestMethod": "grpc", 
    75                "metadata": dict(request_metadata), 
    76            } 
    77            _LOGGER.debug( 
    78                f"Sending request for {client_call_details.method}", 
    79                extra={ 
    80                    "serviceName": "google.logging.v2.MetricsServiceV2", 
    81                    "rpcName": str(client_call_details.method), 
    82                    "request": grpc_request, 
    83                    "metadata": grpc_request["metadata"], 
    84                }, 
    85            ) 
    86        response = await continuation(client_call_details, request) 
    87        if logging_enabled:  # pragma: NO COVER 
    88            response_metadata = await response.trailing_metadata() 
    89            # Convert gRPC metadata `<class 'grpc.aio._metadata.Metadata'>` to list of tuples 
    90            metadata = ( 
    91                dict([(k, str(v)) for k, v in response_metadata]) 
    92                if response_metadata 
    93                else None 
    94            ) 
    95            result = await response 
    96            if isinstance(result, proto.Message): 
    97                response_payload = type(result).to_json(result) 
    98            elif isinstance(result, google.protobuf.message.Message): 
    99                response_payload = MessageToJson(result) 
    100            else: 
    101                response_payload = f"{type(result).__name__}: {pickle.dumps(result)}" 
    102            grpc_response = { 
    103                "payload": response_payload, 
    104                "metadata": metadata, 
    105                "status": "OK", 
    106            } 
    107            _LOGGER.debug( 
    108                f"Received response to rpc {client_call_details.method}.", 
    109                extra={ 
    110                    "serviceName": "google.logging.v2.MetricsServiceV2", 
    111                    "rpcName": str(client_call_details.method), 
    112                    "response": grpc_response, 
    113                    "metadata": grpc_response["metadata"], 
    114                }, 
    115            ) 
    116        return response 
    117 
    118 
    119class MetricsServiceV2GrpcAsyncIOTransport(MetricsServiceV2Transport): 
    120    """gRPC AsyncIO backend transport for MetricsServiceV2. 
    121 
    122    Service for configuring logs-based metrics. 
    123 
    124    This class defines the same methods as the primary client, so the 
    125    primary client can load the underlying transport implementation 
    126    and call it. 
    127 
    128    It sends protocol buffers over the wire using gRPC (which is built on 
    129    top of HTTP/2); the ``grpcio`` package must be installed. 
    130    """ 
    131 
    132    _grpc_channel: aio.Channel 
    133    _stubs: Dict[str, Callable] = {} 
    134 
    135    @classmethod 
    136    def create_channel( 
    137        cls, 
    138        host: str = "logging.googleapis.com", 
    139        credentials: Optional[ga_credentials.Credentials] = None, 
    140        credentials_file: Optional[str] = None, 
    141        scopes: Optional[Sequence[str]] = None, 
    142        quota_project_id: Optional[str] = None, 
    143        **kwargs, 
    144    ) -> aio.Channel: 
    145        """Create and return a gRPC AsyncIO channel object. 
    146        Args: 
    147            host (Optional[str]): The host for the channel to use. 
    148            credentials (Optional[~.Credentials]): The 
    149                authorization credentials to attach to requests. These 
    150                credentials identify this application to the service. If 
    151                none are specified, the client will attempt to ascertain 
    152                the credentials from the environment. 
    153            credentials_file (Optional[str]): A file with credentials that can 
    154                be loaded with :func:`google.auth.load_credentials_from_file`. 
    155            scopes (Optional[Sequence[str]]): A optional list of scopes needed for this 
    156                service. These are only used when credentials are not specified and 
    157                are passed to :func:`google.auth.default`. 
    158            quota_project_id (Optional[str]): An optional project to use for billing 
    159                and quota. 
    160            kwargs (Optional[dict]): Keyword arguments, which are passed to the 
    161                channel creation. 
    162        Returns: 
    163            aio.Channel: A gRPC AsyncIO channel object. 
    164        """ 
    165 
    166        return grpc_helpers_async.create_channel( 
    167            host, 
    168            credentials=credentials, 
    169            credentials_file=credentials_file, 
    170            quota_project_id=quota_project_id, 
    171            default_scopes=cls.AUTH_SCOPES, 
    172            scopes=scopes, 
    173            default_host=cls.DEFAULT_HOST, 
    174            **kwargs, 
    175        ) 
    176 
    177    def __init__( 
    178        self, 
    179        *, 
    180        host: str = "logging.googleapis.com", 
    181        credentials: Optional[ga_credentials.Credentials] = None, 
    182        credentials_file: Optional[str] = None, 
    183        scopes: Optional[Sequence[str]] = None, 
    184        channel: Optional[Union[aio.Channel, Callable[..., aio.Channel]]] = None, 
    185        api_mtls_endpoint: Optional[str] = None, 
    186        client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, 
    187        ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, 
    188        client_cert_source_for_mtls: Optional[Callable[[], Tuple[bytes, bytes]]] = None, 
    189        quota_project_id: Optional[str] = None, 
    190        client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, 
    191        always_use_jwt_access: Optional[bool] = False, 
    192        api_audience: Optional[str] = None, 
    193    ) -> None: 
    194        """Instantiate the transport. 
    195 
    196        Args: 
    197            host (Optional[str]): 
    198                 The hostname to connect to (default: 'logging.googleapis.com'). 
    199            credentials (Optional[google.auth.credentials.Credentials]): The 
    200                authorization credentials to attach to requests. These 
    201                credentials identify the application to the service; if none 
    202                are specified, the client will attempt to ascertain the 
    203                credentials from the environment. 
    204                This argument is ignored if a ``channel`` instance is provided. 
    205            credentials_file (Optional[str]): A file with credentials that can 
    206                be loaded with :func:`google.auth.load_credentials_from_file`. 
    207                This argument is ignored if a ``channel`` instance is provided. 
    208            scopes (Optional[Sequence[str]]): A optional list of scopes needed for this 
    209                service. These are only used when credentials are not specified and 
    210                are passed to :func:`google.auth.default`. 
    211            channel (Optional[Union[aio.Channel, Callable[..., aio.Channel]]]): 
    212                A ``Channel`` instance through which to make calls, or a Callable 
    213                that constructs and returns one. If set to None, ``self.create_channel`` 
    214                is used to create the channel. If a Callable is given, it will be called 
    215                with the same arguments as used in ``self.create_channel``. 
    216            api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. 
    217                If provided, it overrides the ``host`` argument and tries to create 
    218                a mutual TLS channel with client SSL credentials from 
    219                ``client_cert_source`` or application default SSL credentials. 
    220            client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): 
    221                Deprecated. A callback to provide client SSL certificate bytes and 
    222                private key bytes, both in PEM format. It is ignored if 
    223                ``api_mtls_endpoint`` is None. 
    224            ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials 
    225                for the grpc channel. It is ignored if a ``channel`` instance is provided. 
    226            client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): 
    227                A callback to provide client certificate bytes and private key bytes, 
    228                both in PEM format. It is used to configure a mutual TLS channel. It is 
    229                ignored if a ``channel`` instance or ``ssl_channel_credentials`` is provided. 
    230            quota_project_id (Optional[str]): An optional project to use for billing 
    231                and quota. 
    232            client_info (google.api_core.gapic_v1.client_info.ClientInfo): 
    233                The client info used to send a user-agent string along with 
    234                API requests. If ``None``, then default info will be used. 
    235                Generally, you only need to set this if you're developing 
    236                your own client library. 
    237            always_use_jwt_access (Optional[bool]): Whether self signed JWT should 
    238                be used for service account credentials. 
    239 
    240        Raises: 
    241            google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport 
    242              creation failed for any reason. 
    243          google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` 
    244              and ``credentials_file`` are passed. 
    245        """ 
    246        self._grpc_channel = None 
    247        self._ssl_channel_credentials = ssl_channel_credentials 
    248        self._stubs: Dict[str, Callable] = {} 
    249 
    250        if api_mtls_endpoint: 
    251            warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) 
    252        if client_cert_source: 
    253            warnings.warn("client_cert_source is deprecated", DeprecationWarning) 
    254 
    255        if isinstance(channel, aio.Channel): 
    256            # Ignore credentials if a channel was passed. 
    257            credentials = None 
    258            self._ignore_credentials = True 
    259            # If a channel was explicitly provided, set it. 
    260            self._grpc_channel = channel 
    261            self._ssl_channel_credentials = None 
    262        else: 
    263            if api_mtls_endpoint: 
    264                host = api_mtls_endpoint 
    265 
    266                # Create SSL credentials with client_cert_source or application 
    267                # default SSL credentials. 
    268                if client_cert_source: 
    269                    cert, key = client_cert_source() 
    270                    self._ssl_channel_credentials = grpc.ssl_channel_credentials( 
    271                        certificate_chain=cert, private_key=key 
    272                    ) 
    273                else: 
    274                    self._ssl_channel_credentials = SslCredentials().ssl_credentials 
    275 
    276            else: 
    277                if client_cert_source_for_mtls and not ssl_channel_credentials: 
    278                    cert, key = client_cert_source_for_mtls() 
    279                    self._ssl_channel_credentials = grpc.ssl_channel_credentials( 
    280                        certificate_chain=cert, private_key=key 
    281                    ) 
    282 
    283        # The base transport sets the host, credentials and scopes 
    284        super().__init__( 
    285            host=host, 
    286            credentials=credentials, 
    287            credentials_file=credentials_file, 
    288            scopes=scopes, 
    289            quota_project_id=quota_project_id, 
    290            client_info=client_info, 
    291            always_use_jwt_access=always_use_jwt_access, 
    292            api_audience=api_audience, 
    293        ) 
    294 
    295        if not self._grpc_channel: 
    296            # initialize with the provided callable or the default channel 
    297            channel_init = channel or type(self).create_channel 
    298            self._grpc_channel = channel_init( 
    299                self._host, 
    300                # use the credentials which are saved 
    301                credentials=self._credentials, 
    302                # Set ``credentials_file`` to ``None`` here as 
    303                # the credentials that we saved earlier should be used. 
    304                credentials_file=None, 
    305                scopes=self._scopes, 
    306                ssl_credentials=self._ssl_channel_credentials, 
    307                quota_project_id=quota_project_id, 
    308                options=[ 
    309                    ("grpc.max_send_message_length", -1), 
    310                    ("grpc.max_receive_message_length", -1), 
    311                ], 
    312            ) 
    313 
    314        self._interceptor = _LoggingClientAIOInterceptor() 
    315        self._grpc_channel._unary_unary_interceptors.append(self._interceptor) 
    316        self._logged_channel = self._grpc_channel 
    317        self._wrap_with_kind = ( 
    318            "kind" in inspect.signature(gapic_v1.method_async.wrap_method).parameters 
    319        ) 
    320        # Wrap messages. This must be done after self._logged_channel exists 
    321        self._prep_wrapped_messages(client_info) 
    322 
    323    @property 
    324    def grpc_channel(self) -> aio.Channel: 
    325        """Create the channel designed to connect to this service. 
    326 
    327        This property caches on the instance; repeated calls return 
    328        the same channel. 
    329        """ 
    330        # Return the channel from cache. 
    331        return self._grpc_channel 
    332 
    333    @property 
    334    def list_log_metrics( 
    335        self, 
    336    ) -> Callable[ 
    337        [logging_metrics.ListLogMetricsRequest], 
    338        Awaitable[logging_metrics.ListLogMetricsResponse], 
    339    ]: 
    340        r"""Return a callable for the list log metrics method over gRPC. 
    341 
    342        Lists logs-based metrics. 
    343 
    344        Returns: 
    345            Callable[[~.ListLogMetricsRequest], 
    346                    Awaitable[~.ListLogMetricsResponse]]: 
    347                A function that, when called, will call the underlying RPC 
    348                on the server. 
    349        """ 
    350        # Generate a "stub function" on-the-fly which will actually make 
    351        # the request. 
    352        # gRPC handles serialization and deserialization, so we just need 
    353        # to pass in the functions for each. 
    354        if "list_log_metrics" not in self._stubs: 
    355            self._stubs["list_log_metrics"] = self._logged_channel.unary_unary( 
    356                "/google.logging.v2.MetricsServiceV2/ListLogMetrics", 
    357                request_serializer=logging_metrics.ListLogMetricsRequest.serialize, 
    358                response_deserializer=logging_metrics.ListLogMetricsResponse.deserialize, 
    359            ) 
    360        return self._stubs["list_log_metrics"] 
    361 
    362    @property 
    363    def get_log_metric( 
    364        self, 
    365    ) -> Callable[ 
    366        [logging_metrics.GetLogMetricRequest], Awaitable[logging_metrics.LogMetric] 
    367    ]: 
    368        r"""Return a callable for the get log metric method over gRPC. 
    369 
    370        Gets a logs-based metric. 
    371 
    372        Returns: 
    373            Callable[[~.GetLogMetricRequest], 
    374                    Awaitable[~.LogMetric]]: 
    375                A function that, when called, will call the underlying RPC 
    376                on the server. 
    377        """ 
    378        # Generate a "stub function" on-the-fly which will actually make 
    379        # the request. 
    380        # gRPC handles serialization and deserialization, so we just need 
    381        # to pass in the functions for each. 
    382        if "get_log_metric" not in self._stubs: 
    383            self._stubs["get_log_metric"] = self._logged_channel.unary_unary( 
    384                "/google.logging.v2.MetricsServiceV2/GetLogMetric", 
    385                request_serializer=logging_metrics.GetLogMetricRequest.serialize, 
    386                response_deserializer=logging_metrics.LogMetric.deserialize, 
    387            ) 
    388        return self._stubs["get_log_metric"] 
    389 
    390    @property 
    391    def create_log_metric( 
    392        self, 
    393    ) -> Callable[ 
    394        [logging_metrics.CreateLogMetricRequest], Awaitable[logging_metrics.LogMetric] 
    395    ]: 
    396        r"""Return a callable for the create log metric method over gRPC. 
    397 
    398        Creates a logs-based metric. 
    399 
    400        Returns: 
    401            Callable[[~.CreateLogMetricRequest], 
    402                    Awaitable[~.LogMetric]]: 
    403                A function that, when called, will call the underlying RPC 
    404                on the server. 
    405        """ 
    406        # Generate a "stub function" on-the-fly which will actually make 
    407        # the request. 
    408        # gRPC handles serialization and deserialization, so we just need 
    409        # to pass in the functions for each. 
    410        if "create_log_metric" not in self._stubs: 
    411            self._stubs["create_log_metric"] = self._logged_channel.unary_unary( 
    412                "/google.logging.v2.MetricsServiceV2/CreateLogMetric", 
    413                request_serializer=logging_metrics.CreateLogMetricRequest.serialize, 
    414                response_deserializer=logging_metrics.LogMetric.deserialize, 
    415            ) 
    416        return self._stubs["create_log_metric"] 
    417 
    418    @property 
    419    def update_log_metric( 
    420        self, 
    421    ) -> Callable[ 
    422        [logging_metrics.UpdateLogMetricRequest], Awaitable[logging_metrics.LogMetric] 
    423    ]: 
    424        r"""Return a callable for the update log metric method over gRPC. 
    425 
    426        Creates or updates a logs-based metric. 
    427 
    428        Returns: 
    429            Callable[[~.UpdateLogMetricRequest], 
    430                    Awaitable[~.LogMetric]]: 
    431                A function that, when called, will call the underlying RPC 
    432                on the server. 
    433        """ 
    434        # Generate a "stub function" on-the-fly which will actually make 
    435        # the request. 
    436        # gRPC handles serialization and deserialization, so we just need 
    437        # to pass in the functions for each. 
    438        if "update_log_metric" not in self._stubs: 
    439            self._stubs["update_log_metric"] = self._logged_channel.unary_unary( 
    440                "/google.logging.v2.MetricsServiceV2/UpdateLogMetric", 
    441                request_serializer=logging_metrics.UpdateLogMetricRequest.serialize, 
    442                response_deserializer=logging_metrics.LogMetric.deserialize, 
    443            ) 
    444        return self._stubs["update_log_metric"] 
    445 
    446    @property 
    447    def delete_log_metric( 
    448        self, 
    449    ) -> Callable[[logging_metrics.DeleteLogMetricRequest], Awaitable[empty_pb2.Empty]]: 
    450        r"""Return a callable for the delete log metric method over gRPC. 
    451 
    452        Deletes a logs-based metric. 
    453 
    454        Returns: 
    455            Callable[[~.DeleteLogMetricRequest], 
    456                    Awaitable[~.Empty]]: 
    457                A function that, when called, will call the underlying RPC 
    458                on the server. 
    459        """ 
    460        # Generate a "stub function" on-the-fly which will actually make 
    461        # the request. 
    462        # gRPC handles serialization and deserialization, so we just need 
    463        # to pass in the functions for each. 
    464        if "delete_log_metric" not in self._stubs: 
    465            self._stubs["delete_log_metric"] = self._logged_channel.unary_unary( 
    466                "/google.logging.v2.MetricsServiceV2/DeleteLogMetric", 
    467                request_serializer=logging_metrics.DeleteLogMetricRequest.serialize, 
    468                response_deserializer=empty_pb2.Empty.FromString, 
    469            ) 
    470        return self._stubs["delete_log_metric"] 
    471 
    472    def _prep_wrapped_messages(self, client_info): 
    473        """Precompute the wrapped methods, overriding the base class method to use async wrappers.""" 
    474        self._wrapped_methods = { 
    475            self.list_log_metrics: self._wrap_method( 
    476                self.list_log_metrics, 
    477                default_retry=retries.AsyncRetry( 
    478                    initial=0.1, 
    479                    maximum=60.0, 
    480                    multiplier=1.3, 
    481                    predicate=retries.if_exception_type( 
    482                        core_exceptions.DeadlineExceeded, 
    483                        core_exceptions.InternalServerError, 
    484                        core_exceptions.ServiceUnavailable, 
    485                    ), 
    486                    deadline=60.0, 
    487                ), 
    488                default_timeout=60.0, 
    489                client_info=client_info, 
    490            ), 
    491            self.get_log_metric: self._wrap_method( 
    492                self.get_log_metric, 
    493                default_retry=retries.AsyncRetry( 
    494                    initial=0.1, 
    495                    maximum=60.0, 
    496                    multiplier=1.3, 
    497                    predicate=retries.if_exception_type( 
    498                        core_exceptions.DeadlineExceeded, 
    499                        core_exceptions.InternalServerError, 
    500                        core_exceptions.ServiceUnavailable, 
    501                    ), 
    502                    deadline=60.0, 
    503                ), 
    504                default_timeout=60.0, 
    505                client_info=client_info, 
    506            ), 
    507            self.create_log_metric: self._wrap_method( 
    508                self.create_log_metric, 
    509                default_timeout=60.0, 
    510                client_info=client_info, 
    511            ), 
    512            self.update_log_metric: self._wrap_method( 
    513                self.update_log_metric, 
    514                default_retry=retries.AsyncRetry( 
    515                    initial=0.1, 
    516                    maximum=60.0, 
    517                    multiplier=1.3, 
    518                    predicate=retries.if_exception_type( 
    519                        core_exceptions.DeadlineExceeded, 
    520                        core_exceptions.InternalServerError, 
    521                        core_exceptions.ServiceUnavailable, 
    522                    ), 
    523                    deadline=60.0, 
    524                ), 
    525                default_timeout=60.0, 
    526                client_info=client_info, 
    527            ), 
    528            self.delete_log_metric: self._wrap_method( 
    529                self.delete_log_metric, 
    530                default_retry=retries.AsyncRetry( 
    531                    initial=0.1, 
    532                    maximum=60.0, 
    533                    multiplier=1.3, 
    534                    predicate=retries.if_exception_type( 
    535                        core_exceptions.DeadlineExceeded, 
    536                        core_exceptions.InternalServerError, 
    537                        core_exceptions.ServiceUnavailable, 
    538                    ), 
    539                    deadline=60.0, 
    540                ), 
    541                default_timeout=60.0, 
    542                client_info=client_info, 
    543            ), 
    544            self.cancel_operation: self._wrap_method( 
    545                self.cancel_operation, 
    546                default_timeout=None, 
    547                client_info=client_info, 
    548            ), 
    549            self.get_operation: self._wrap_method( 
    550                self.get_operation, 
    551                default_timeout=None, 
    552                client_info=client_info, 
    553            ), 
    554            self.list_operations: self._wrap_method( 
    555                self.list_operations, 
    556                default_timeout=None, 
    557                client_info=client_info, 
    558            ), 
    559        } 
    560 
    561    def _wrap_method(self, func, *args, **kwargs): 
    562        if self._wrap_with_kind:  # pragma: NO COVER 
    563            kwargs["kind"] = self.kind 
    564        return gapic_v1.method_async.wrap_method(func, *args, **kwargs) 
    565 
    566    def close(self): 
    567        return self._logged_channel.close() 
    568 
    569    @property 
    570    def kind(self) -> str: 
    571        return "grpc_asyncio" 
    572 
    573    @property 
    574    def cancel_operation( 
    575        self, 
    576    ) -> Callable[[operations_pb2.CancelOperationRequest], None]: 
    577        r"""Return a callable for the cancel_operation method over gRPC.""" 
    578        # Generate a "stub function" on-the-fly which will actually make 
    579        # the request. 
    580        # gRPC handles serialization and deserialization, so we just need 
    581        # to pass in the functions for each. 
    582        if "cancel_operation" not in self._stubs: 
    583            self._stubs["cancel_operation"] = self._logged_channel.unary_unary( 
    584                "/google.longrunning.Operations/CancelOperation", 
    585                request_serializer=operations_pb2.CancelOperationRequest.SerializeToString, 
    586                response_deserializer=None, 
    587            ) 
    588        return self._stubs["cancel_operation"] 
    589 
    590    @property 
    591    def get_operation( 
    592        self, 
    593    ) -> Callable[[operations_pb2.GetOperationRequest], operations_pb2.Operation]: 
    594        r"""Return a callable for the get_operation method over gRPC.""" 
    595        # Generate a "stub function" on-the-fly which will actually make 
    596        # the request. 
    597        # gRPC handles serialization and deserialization, so we just need 
    598        # to pass in the functions for each. 
    599        if "get_operation" not in self._stubs: 
    600            self._stubs["get_operation"] = self._logged_channel.unary_unary( 
    601                "/google.longrunning.Operations/GetOperation", 
    602                request_serializer=operations_pb2.GetOperationRequest.SerializeToString, 
    603                response_deserializer=operations_pb2.Operation.FromString, 
    604            ) 
    605        return self._stubs["get_operation"] 
    606 
    607    @property 
    608    def list_operations( 
    609        self, 
    610    ) -> Callable[ 
    611        [operations_pb2.ListOperationsRequest], operations_pb2.ListOperationsResponse 
    612    ]: 
    613        r"""Return a callable for the list_operations method over gRPC.""" 
    614        # Generate a "stub function" on-the-fly which will actually make 
    615        # the request. 
    616        # gRPC handles serialization and deserialization, so we just need 
    617        # to pass in the functions for each. 
    618        if "list_operations" not in self._stubs: 
    619            self._stubs["list_operations"] = self._logged_channel.unary_unary( 
    620                "/google.longrunning.Operations/ListOperations", 
    621                request_serializer=operations_pb2.ListOperationsRequest.SerializeToString, 
    622                response_deserializer=operations_pb2.ListOperationsResponse.FromString, 
    623            ) 
    624        return self._stubs["list_operations"] 
    625 
    626 
    627__all__ = ("MetricsServiceV2GrpcAsyncIOTransport",)