diff --git a/google/analytics/data_v1beta/services/beta_analytics_data/async_client.py b/google/analytics/data_v1beta/services/beta_analytics_data/async_client.py index c07fd7a..ccfa59d 100644 --- a/google/analytics/data_v1beta/services/beta_analytics_data/async_client.py +++ b/google/analytics/data_v1beta/services/beta_analytics_data/async_client.py @@ -578,6 +578,12 @@ async def check_compatibility( # 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/analytics/data_v1beta/services/beta_analytics_data/client.py b/google/analytics/data_v1beta/services/beta_analytics_data/client.py index 1053b4c..8c056f3 100644 --- a/google/analytics/data_v1beta/services/beta_analytics_data/client.py +++ b/google/analytics/data_v1beta/services/beta_analytics_data/client.py @@ -341,10 +341,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 run_report( @@ -770,6 +767,19 @@ def check_compatibility( # 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/analytics/data_v1beta/services/beta_analytics_data/transports/base.py b/google/analytics/data_v1beta/services/beta_analytics_data/transports/base.py index 7f4eb54..98511b7 100644 --- a/google/analytics/data_v1beta/services/beta_analytics_data/transports/base.py +++ b/google/analytics/data_v1beta/services/beta_analytics_data/transports/base.py @@ -180,6 +180,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 run_report( self, diff --git a/google/analytics/data_v1beta/services/beta_analytics_data/transports/grpc.py b/google/analytics/data_v1beta/services/beta_analytics_data/transports/grpc.py index 85b78fc..fe7c668 100644 --- a/google/analytics/data_v1beta/services/beta_analytics_data/transports/grpc.py +++ b/google/analytics/data_v1beta/services/beta_analytics_data/transports/grpc.py @@ -462,5 +462,8 @@ def check_compatibility( ) return self._stubs["check_compatibility"] + def close(self): + self.grpc_channel.close() + __all__ = ("BetaAnalyticsDataGrpcTransport",) diff --git a/google/analytics/data_v1beta/services/beta_analytics_data/transports/grpc_asyncio.py b/google/analytics/data_v1beta/services/beta_analytics_data/transports/grpc_asyncio.py index 2a9682a..6a43694 100644 --- a/google/analytics/data_v1beta/services/beta_analytics_data/transports/grpc_asyncio.py +++ b/google/analytics/data_v1beta/services/beta_analytics_data/transports/grpc_asyncio.py @@ -468,5 +468,8 @@ def check_compatibility( ) return self._stubs["check_compatibility"] + def close(self): + return self.grpc_channel.close() + __all__ = ("BetaAnalyticsDataGrpcAsyncIOTransport",) diff --git a/google/analytics/data_v1beta/types/analytics_data_api.py b/google/analytics/data_v1beta/types/analytics_data_api.py index 08357c3..ee3837a 100644 --- a/google/analytics/data_v1beta/types/analytics_data_api.py +++ b/google/analytics/data_v1beta/types/analytics_data_api.py @@ -129,6 +129,7 @@ class Metadata(proto.Message): class RunReportRequest(proto.Message): r"""The request to generate a report. + Attributes: property (str): A Google Analytics GA4 property identifier whose events are @@ -235,6 +236,7 @@ class RunReportRequest(proto.Message): class RunReportResponse(proto.Message): r"""The response report table corresponding to a request. + Attributes: dimension_headers (Sequence[google.analytics.data_v1beta.types.DimensionHeader]): Describes dimension columns. The number of @@ -295,6 +297,7 @@ class RunReportResponse(proto.Message): class RunPivotReportRequest(proto.Message): r"""The request to generate a pivot report. + Attributes: property (str): A Google Analytics GA4 property identifier whose events are @@ -467,6 +470,7 @@ class RunPivotReportResponse(proto.Message): class BatchRunReportsRequest(proto.Message): r"""The batch request containing multiple report requests. + Attributes: property (str): A Google Analytics GA4 property identifier whose events are @@ -490,6 +494,7 @@ class BatchRunReportsRequest(proto.Message): class BatchRunReportsResponse(proto.Message): r"""The batch response containing multiple reports. + Attributes: reports (Sequence[google.analytics.data_v1beta.types.RunReportResponse]): Individual responses. Each response has a @@ -507,6 +512,7 @@ class BatchRunReportsResponse(proto.Message): class BatchRunPivotReportsRequest(proto.Message): r"""The batch request containing multiple pivot report requests. + Attributes: property (str): A Google Analytics GA4 property identifier whose events are @@ -532,6 +538,7 @@ class BatchRunPivotReportsRequest(proto.Message): class BatchRunPivotReportsResponse(proto.Message): r"""The batch response containing multiple pivot reports. + Attributes: pivot_reports (Sequence[google.analytics.data_v1beta.types.RunPivotReportResponse]): Individual responses. Each response has a @@ -551,6 +558,7 @@ class BatchRunPivotReportsResponse(proto.Message): class GetMetadataRequest(proto.Message): r"""Request for a property's dimension and metric metadata. + Attributes: name (str): Required. The resource name of the metadata to retrieve. @@ -572,6 +580,7 @@ class GetMetadataRequest(proto.Message): class RunRealtimeReportRequest(proto.Message): r"""The request to generate a realtime report. + Attributes: property (str): A Google Analytics GA4 property identifier whose events are diff --git a/google/analytics/data_v1beta/types/data.py b/google/analytics/data_v1beta/types/data.py index 97d3d99..aac76c1 100644 --- a/google/analytics/data_v1beta/types/data.py +++ b/google/analytics/data_v1beta/types/data.py @@ -218,6 +218,7 @@ class DimensionExpression(proto.Message): class CaseExpression(proto.Message): r"""Used to convert a dimension value to a single case. + Attributes: dimension_name (str): Name of a dimension. The name must refer back @@ -228,6 +229,7 @@ class CaseExpression(proto.Message): class ConcatenateExpression(proto.Message): r"""Used to combine dimension values to a single dimension. + Attributes: dimension_names (Sequence[str]): Names of dimensions. The names must refer @@ -326,6 +328,7 @@ class FilterExpression(proto.Message): class FilterExpressionList(proto.Message): r"""A list of filter expressions. + Attributes: expressions (Sequence[google.analytics.data_v1beta.types.FilterExpression]): A list of filter expressions. @@ -338,6 +341,7 @@ class FilterExpressionList(proto.Message): class Filter(proto.Message): r"""An expression to filter dimension or metric values. + Attributes: field_name (str): The dimension name or metric name. Must be a @@ -354,6 +358,7 @@ class Filter(proto.Message): class StringFilter(proto.Message): r"""The filter for string + Attributes: match_type (google.analytics.data_v1beta.types.Filter.StringFilter.MatchType): The match type for this filter. @@ -381,6 +386,7 @@ class MatchType(proto.Enum): class InListFilter(proto.Message): r"""The result needs to be in a list of string values. + Attributes: values (Sequence[str]): The list of string values. @@ -394,6 +400,7 @@ class InListFilter(proto.Message): class NumericFilter(proto.Message): r"""Filters for numeric or date values. + Attributes: operation (google.analytics.data_v1beta.types.Filter.NumericFilter.Operation): The operation type for this filter. @@ -446,6 +453,7 @@ class BetweenFilter(proto.Message): class OrderBy(proto.Message): r"""The sort options. + Attributes: metric (google.analytics.data_v1beta.types.OrderBy.MetricOrderBy): Sorts results by a metric's values. @@ -460,6 +468,7 @@ class OrderBy(proto.Message): class MetricOrderBy(proto.Message): r"""Sorts by metric values. + Attributes: metric_name (str): A metric name in the request to order by. @@ -469,6 +478,7 @@ class MetricOrderBy(proto.Message): class DimensionOrderBy(proto.Message): r"""Sorts by dimension values. + Attributes: dimension_name (str): A dimension name in the request to order by. @@ -491,6 +501,7 @@ class OrderType(proto.Enum): class PivotOrderBy(proto.Message): r"""Sorts by a pivot column group. + Attributes: metric_name (str): In the response to order by, order rows by @@ -747,6 +758,7 @@ class Granularity(proto.Enum): class CohortReportSettings(proto.Message): r"""Optional settings of a cohort report. + Attributes: accumulate (bool): If true, accumulates the result from first touch day to the @@ -805,6 +817,7 @@ class MetricHeader(proto.Message): class PivotHeader(proto.Message): r"""Dimensions' values in a single pivot. + Attributes: pivot_dimension_headers (Sequence[google.analytics.data_v1beta.types.PivotDimensionHeader]): The size is the same as the cardinality of @@ -823,6 +836,7 @@ class PivotHeader(proto.Message): class PivotDimensionHeader(proto.Message): r"""Summarizes dimension values from a row for this pivot. + Attributes: dimension_values (Sequence[google.analytics.data_v1beta.types.DimensionValue]): Values of multiple dimensions in a pivot. @@ -888,6 +902,7 @@ class Row(proto.Message): class DimensionValue(proto.Message): r"""The value of a dimension. + Attributes: value (str): Value as a string if the dimension type is a @@ -899,6 +914,7 @@ class DimensionValue(proto.Message): class MetricValue(proto.Message): r"""The value of a metric. + Attributes: value (str): Measurement value. See MetricHeader for type. @@ -909,6 +925,7 @@ class MetricValue(proto.Message): class NumericValue(proto.Message): r"""To represent a number. + Attributes: int64_value (int): Integer value @@ -970,6 +987,7 @@ class PropertyQuota(proto.Message): class QuotaStatus(proto.Message): r"""Current state for a particular quota group. + Attributes: consumed (int): Quota consumed by this request. @@ -983,6 +1001,7 @@ class QuotaStatus(proto.Message): class DimensionMetadata(proto.Message): r"""Explains a dimension. + Attributes: api_name (str): This dimension's name. Useable in @@ -1019,6 +1038,7 @@ class DimensionMetadata(proto.Message): class MetricMetadata(proto.Message): r"""Explains a metric. + Attributes: api_name (str): A metric name. Useable in `Metric <#Metric>`__'s ``name``. @@ -1063,6 +1083,7 @@ class MetricMetadata(proto.Message): class DimensionCompatibility(proto.Message): r"""The compatibility for a single dimension. + Attributes: dimension_metadata (google.analytics.data_v1beta.types.DimensionMetadata): The dimension metadata contains the API name @@ -1085,6 +1106,7 @@ class DimensionCompatibility(proto.Message): class MetricCompatibility(proto.Message): r"""The compatibility for a single metric. + Attributes: metric_metadata (google.analytics.data_v1beta.types.MetricMetadata): The metric metadata contains the API name for diff --git a/tests/unit/gapic/data_v1beta/test_beta_analytics_data.py b/tests/unit/gapic/data_v1beta/test_beta_analytics_data.py index 7a61a54..2ce45e7 100644 --- a/tests/unit/gapic/data_v1beta/test_beta_analytics_data.py +++ b/tests/unit/gapic/data_v1beta/test_beta_analytics_data.py @@ -41,6 +41,7 @@ from google.api_core import gapic_v1 from google.api_core import grpc_helpers from google.api_core import grpc_helpers_async +from google.api_core import path_template from google.auth import credentials as ga_credentials from google.auth.exceptions import MutualTLSChannelError from google.oauth2 import service_account @@ -1683,6 +1684,9 @@ def test_beta_analytics_data_base_transport(): with pytest.raises(NotImplementedError): getattr(transport, method)(request=object()) + with pytest.raises(NotImplementedError): + transport.close() + @requires_google_auth_gte_1_25_0 def test_beta_analytics_data_base_transport_with_credentials_file(): @@ -2182,3 +2186,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 = BetaAnalyticsDataAsyncClient( + 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 = BetaAnalyticsDataClient( + 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 = BetaAnalyticsDataClient( + 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()