diff --git a/google/cloud/channel_v1/services/cloud_channel_service/async_client.py b/google/cloud/channel_v1/services/cloud_channel_service/async_client.py index 6e1567e..55bac3a 100644 --- a/google/cloud/channel_v1/services/cloud_channel_service/async_client.py +++ b/google/cloud/channel_v1/services/cloud_channel_service/async_client.py @@ -2857,6 +2857,12 @@ async def list_subscribers( # Done; return the response. return response + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/channel_v1/services/cloud_channel_service/client.py b/google/cloud/channel_v1/services/cloud_channel_service/client.py index 6910f62..d384694 100644 --- a/google/cloud/channel_v1/services/cloud_channel_service/client.py +++ b/google/cloud/channel_v1/services/cloud_channel_service/client.py @@ -427,10 +427,7 @@ def __init__( client_cert_source_for_mtls=client_cert_source_func, quota_project_id=client_options.quota_project_id, client_info=client_info, - always_use_jwt_access=( - Transport == type(self).get_transport_class("grpc") - or Transport == type(self).get_transport_class("grpc_asyncio") - ), + always_use_jwt_access=True, ) def list_customers( @@ -3126,6 +3123,19 @@ def list_subscribers( # Done; return the response. return response + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/channel_v1/services/cloud_channel_service/transports/base.py b/google/cloud/channel_v1/services/cloud_channel_service/transports/base.py index 5846bdb..e0f2d36 100644 --- a/google/cloud/channel_v1/services/cloud_channel_service/transports/base.py +++ b/google/cloud/channel_v1/services/cloud_channel_service/transports/base.py @@ -296,6 +296,15 @@ def _prep_wrapped_messages(self, client_info): ), } + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + @property def operations_client(self) -> operations_v1.OperationsClient: """Return the client designed to process long-running operations.""" diff --git a/google/cloud/channel_v1/services/cloud_channel_service/transports/grpc.py b/google/cloud/channel_v1/services/cloud_channel_service/transports/grpc.py index a20533a..6339fa7 100644 --- a/google/cloud/channel_v1/services/cloud_channel_service/transports/grpc.py +++ b/google/cloud/channel_v1/services/cloud_channel_service/transports/grpc.py @@ -1866,5 +1866,8 @@ def list_subscribers( ) return self._stubs["list_subscribers"] + def close(self): + self.grpc_channel.close() + __all__ = ("CloudChannelServiceGrpcTransport",) diff --git a/google/cloud/channel_v1/services/cloud_channel_service/transports/grpc_asyncio.py b/google/cloud/channel_v1/services/cloud_channel_service/transports/grpc_asyncio.py index f353839..18698f2 100644 --- a/google/cloud/channel_v1/services/cloud_channel_service/transports/grpc_asyncio.py +++ b/google/cloud/channel_v1/services/cloud_channel_service/transports/grpc_asyncio.py @@ -1907,5 +1907,8 @@ def list_subscribers( ) return self._stubs["list_subscribers"] + def close(self): + return self.grpc_channel.close() + __all__ = ("CloudChannelServiceGrpcAsyncIOTransport",) diff --git a/google/cloud/channel_v1/types/common.py b/google/cloud/channel_v1/types/common.py index 33b5a77..f088211 100644 --- a/google/cloud/channel_v1/types/common.py +++ b/google/cloud/channel_v1/types/common.py @@ -26,6 +26,7 @@ class EduData(proto.Message): r"""Required Edu Attributes + Attributes: institute_type (google.cloud.channel_v1.types.EduData.InstituteType): Designated institute type of customer. @@ -60,6 +61,7 @@ class InstituteSize(proto.Enum): class CloudIdentityInfo(proto.Message): r"""Cloud Identity information for the Cloud Channel Customer. + Attributes: customer_type (google.cloud.channel_v1.types.CloudIdentityInfo.CustomerType): CustomerType indicates verification type @@ -105,6 +107,7 @@ class CustomerType(proto.Enum): class Value(proto.Message): r"""Data type and value of a parameter. + Attributes: int64_value (int): Represents an int64 value. diff --git a/google/cloud/channel_v1/types/customers.py b/google/cloud/channel_v1/types/customers.py index b6d3b7f..10c24d0 100644 --- a/google/cloud/channel_v1/types/customers.py +++ b/google/cloud/channel_v1/types/customers.py @@ -27,6 +27,7 @@ class Customer(proto.Message): r"""Entity representing a customer of a reseller or distributor. + Attributes: name (str): Output only. Resource name of the customer. Format: @@ -98,6 +99,7 @@ class Customer(proto.Message): class ContactInfo(proto.Message): r"""Contact information for a customer account. + Attributes: first_name (str): The customer account contact's first name. diff --git a/google/cloud/channel_v1/types/entitlements.py b/google/cloud/channel_v1/types/entitlements.py index 2c347ba..a45944f 100644 --- a/google/cloud/channel_v1/types/entitlements.py +++ b/google/cloud/channel_v1/types/entitlements.py @@ -126,6 +126,7 @@ class SuspensionReason(proto.Enum): class Parameter(proto.Message): r"""Definition for extended entitlement parameters. + Attributes: name (str): Name of the parameter. @@ -158,6 +159,7 @@ class AssociationInfo(proto.Message): class ProvisionedService(proto.Message): r"""Service provisioned for an entitlement. + Attributes: provisioning_id (str): Output only. Provisioning ID of the @@ -178,6 +180,7 @@ class ProvisionedService(proto.Message): class CommitmentSettings(proto.Message): r"""Commitment settings for commitment-based offers. + Attributes: start_time (google.protobuf.timestamp_pb2.Timestamp): Output only. Commitment start timestamp. @@ -195,6 +198,7 @@ class CommitmentSettings(proto.Message): class RenewalSettings(proto.Message): r"""Renewal settings for renewable Offers. + Attributes: enable_renewal (bool): If false, the plan will be completed at the @@ -218,6 +222,7 @@ class RenewalSettings(proto.Message): class TrialSettings(proto.Message): r"""Settings for trial offers. + Attributes: trial (bool): Determines if the entitlement is in a trial or not: @@ -259,6 +264,7 @@ class TransferableSku(proto.Message): class TransferEligibility(proto.Message): r"""Specifies transfer eligibility of a SKU. + Attributes: is_eligible (bool): Whether reseller is eligible to transfer the diff --git a/google/cloud/channel_v1/types/offers.py b/google/cloud/channel_v1/types/offers.py index 3d1f3dc..876ea73 100644 --- a/google/cloud/channel_v1/types/offers.py +++ b/google/cloud/channel_v1/types/offers.py @@ -185,6 +185,7 @@ class ParameterType(proto.Enum): class Constraints(proto.Message): r"""Represents the constraints for buying the Offer. + Attributes: customer_constraints (google.cloud.channel_v1.types.CustomerConstraints): Represents constraints required to purchase @@ -255,6 +256,7 @@ class Plan(proto.Message): class PriceByResource(proto.Message): r"""Represents price by resource type. + Attributes: resource_type (google.cloud.channel_v1.types.ResourceType): Resource Type. Example: SEAT @@ -272,6 +274,7 @@ class PriceByResource(proto.Message): class Price(proto.Message): r"""Represents the price of the Offer. + Attributes: base_price (google.type.money_pb2.Money): Base price. @@ -346,6 +349,7 @@ class PriceTier(proto.Message): class Period(proto.Message): r"""Represents period in days/months/years. + Attributes: duration (int): Total duration of Period Type defined. diff --git a/google/cloud/channel_v1/types/products.py b/google/cloud/channel_v1/types/products.py index 6f15a96..5bda6a3 100644 --- a/google/cloud/channel_v1/types/products.py +++ b/google/cloud/channel_v1/types/products.py @@ -85,6 +85,7 @@ class MarketingInfo(proto.Message): class Media(proto.Message): r"""Represents media information. + Attributes: title (str): Title of the media. diff --git a/google/cloud/channel_v1/types/service.py b/google/cloud/channel_v1/types/service.py index f578689..82a9de7 100644 --- a/google/cloud/channel_v1/types/service.py +++ b/google/cloud/channel_v1/types/service.py @@ -825,6 +825,7 @@ class TransferEntitlementsToGoogleRequest(proto.Message): class ChangeParametersRequest(proto.Message): r"""Request message for [CloudChannelService.ChangeParametersRequest][]. + Attributes: name (str): Required. The name of the entitlement to update. Name uses @@ -1062,6 +1063,7 @@ class ActivateEntitlementRequest(proto.Message): class LookupOfferRequest(proto.Message): r"""Request message for LookupOffer. + Attributes: entitlement (str): Required. The resource name of the entitlement to retrieve @@ -1074,6 +1076,7 @@ class LookupOfferRequest(proto.Message): class ListProductsRequest(proto.Message): r"""Request message for ListProducts. + Attributes: account (str): Required. The resource name of the reseller account. Format: @@ -1102,6 +1105,7 @@ class ListProductsRequest(proto.Message): class ListProductsResponse(proto.Message): r"""Response message for ListProducts. + Attributes: products (Sequence[google.cloud.channel_v1.types.Product]): List of Products requested. @@ -1121,6 +1125,7 @@ def raw_page(self): class ListSkusRequest(proto.Message): r"""Request message for ListSkus. + Attributes: parent (str): Required. The resource name of the Product to list SKUs for. @@ -1154,6 +1159,7 @@ class ListSkusRequest(proto.Message): class ListSkusResponse(proto.Message): r"""Response message for ListSkus. + Attributes: skus (Sequence[google.cloud.channel_v1.types.Sku]): The list of SKUs requested. @@ -1171,6 +1177,7 @@ def raw_page(self): class ListOffersRequest(proto.Message): r"""Request message for ListOffers. + Attributes: parent (str): Required. The resource name of the reseller account from @@ -1208,6 +1215,7 @@ class ListOffersRequest(proto.Message): class ListOffersResponse(proto.Message): r"""Response message for ListOffers. + Attributes: offers (Sequence[google.cloud.channel_v1.types.Offer]): The list of Offers requested. @@ -1225,6 +1233,7 @@ def raw_page(self): class ListPurchasableSkusRequest(proto.Message): r"""Request message for ListPurchasableSkus. + Attributes: create_entitlement_purchase (google.cloud.channel_v1.types.ListPurchasableSkusRequest.CreateEntitlementPurchase): List SKUs for CreateEntitlement purchase. @@ -1306,6 +1315,7 @@ class ChangeType(proto.Enum): class ListPurchasableSkusResponse(proto.Message): r"""Response message for ListPurchasableSkus. + Attributes: purchasable_skus (Sequence[google.cloud.channel_v1.types.PurchasableSku]): The list of SKUs requested. @@ -1337,6 +1347,7 @@ class PurchasableSku(proto.Message): class ListPurchasableOffersRequest(proto.Message): r"""Request message for ListPurchasableOffers. + Attributes: create_entitlement_purchase (google.cloud.channel_v1.types.ListPurchasableOffersRequest.CreateEntitlementPurchase): List Offers for CreateEntitlement purchase. @@ -1363,6 +1374,7 @@ class ListPurchasableOffersRequest(proto.Message): class CreateEntitlementPurchase(proto.Message): r"""List Offers for CreateEntitlement purchase. + Attributes: sku (str): Required. SKU that the result should be restricted to. @@ -1373,6 +1385,7 @@ class CreateEntitlementPurchase(proto.Message): class ChangeOfferPurchase(proto.Message): r"""List Offers for ChangeOffer purchase. + Attributes: entitlement (str): Required. Resource name of the entitlement. Format: @@ -1403,6 +1416,7 @@ class ChangeOfferPurchase(proto.Message): class ListPurchasableOffersResponse(proto.Message): r"""Response message for ListPurchasableOffers. + Attributes: purchasable_offers (Sequence[google.cloud.channel_v1.types.PurchasableOffer]): The list of Offers requested. @@ -1434,6 +1448,7 @@ class PurchasableOffer(proto.Message): class RegisterSubscriberRequest(proto.Message): r"""Request Message for RegisterSubscriber. + Attributes: account (str): Required. Resource name of the account. @@ -1448,6 +1463,7 @@ class RegisterSubscriberRequest(proto.Message): class RegisterSubscriberResponse(proto.Message): r"""Response Message for RegisterSubscriber. + Attributes: topic (str): Name of the topic the subscriber will listen @@ -1459,6 +1475,7 @@ class RegisterSubscriberResponse(proto.Message): class UnregisterSubscriberRequest(proto.Message): r"""Request Message for UnregisterSubscriber. + Attributes: account (str): Required. Resource name of the account. @@ -1473,6 +1490,7 @@ class UnregisterSubscriberRequest(proto.Message): class UnregisterSubscriberResponse(proto.Message): r"""Response Message for UnregisterSubscriber. + Attributes: topic (str): Name of the topic the service account @@ -1484,6 +1502,7 @@ class UnregisterSubscriberResponse(proto.Message): class ListSubscribersRequest(proto.Message): r"""Request Message for ListSubscribers. + Attributes: account (str): Required. Resource name of the account. @@ -1510,6 +1529,7 @@ class ListSubscribersRequest(proto.Message): class ListSubscribersResponse(proto.Message): r"""Response Message for ListSubscribers. + Attributes: topic (str): Name of the topic registered with the diff --git a/tests/unit/gapic/channel_v1/test_cloud_channel_service.py b/tests/unit/gapic/channel_v1/test_cloud_channel_service.py index 1f6cc1f..1cc90eb 100644 --- a/tests/unit/gapic/channel_v1/test_cloud_channel_service.py +++ b/tests/unit/gapic/channel_v1/test_cloud_channel_service.py @@ -32,6 +32,7 @@ from google.api_core import grpc_helpers_async from google.api_core import operation_async # type: ignore from google.api_core import operations_v1 +from google.api_core import path_template from google.auth import credentials as ga_credentials from google.auth.exceptions import MutualTLSChannelError from google.cloud.channel_v1.services.cloud_channel_service import ( @@ -7563,6 +7564,9 @@ def test_cloud_channel_service_base_transport(): with pytest.raises(NotImplementedError): getattr(transport, method)(request=object()) + with pytest.raises(NotImplementedError): + transport.close() + # Additionally, the LRO client (a property) should # also raise NotImplementedError with pytest.raises(NotImplementedError): @@ -8158,3 +8162,49 @@ def test_client_withDEFAULT_CLIENT_INFO(): credentials=ga_credentials.AnonymousCredentials(), client_info=client_info, ) prep.assert_called_once_with(client_info) + + +@pytest.mark.asyncio +async def test_transport_close_async(): + client = CloudChannelServiceAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), transport="grpc_asyncio", + ) + with mock.patch.object( + type(getattr(client.transport, "grpc_channel")), "close" + ) as close: + async with client: + close.assert_not_called() + close.assert_called_once() + + +def test_transport_close(): + transports = { + "grpc": "_grpc_channel", + } + + for transport, close_name in transports.items(): + client = CloudChannelServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport=transport + ) + with mock.patch.object( + type(getattr(client.transport, close_name)), "close" + ) as close: + with client: + close.assert_not_called() + close.assert_called_once() + + +def test_client_ctx(): + transports = [ + "grpc", + ] + for transport in transports: + client = CloudChannelServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport=transport + ) + # Test client calls underlying transport. + with mock.patch.object(type(client.transport), "close") as close: + close.assert_not_called() + with client: + pass + close.assert_called()