From a55bc93b9dea6f5174e47d7250eae45e72608678 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Wed, 17 Mar 2021 08:18:22 -0700 Subject: [PATCH 1/8] build(python): fail nox sessions if a python version is missing (#51) Nox's default behavior is to quietly skip if a python interpreter is missing. https://nox.thea.codes/en/stable/usage.html#failing-sessions-when-the-interpreter-is-missing Source-Author: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Source-Date: Tue Mar 16 13:38:02 2021 -0600 Source-Repo: googleapis/synthtool Source-Sha: eda422b90c3dde4a872a13e6b78a8f802c40d0db Source-Link: https://github.com/googleapis/synthtool/commit/eda422b90c3dde4a872a13e6b78a8f802c40d0db --- noxfile.py | 3 +++ synth.metadata | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/noxfile.py b/noxfile.py index 08d9470..1f30a08 100644 --- a/noxfile.py +++ b/noxfile.py @@ -41,6 +41,9 @@ "docs", ] +# Error if a python version is missing +nox.options.error_on_missing_interpreters = True + @nox.session(python=DEFAULT_PYTHON_VERSION) def lint(session): diff --git a/synth.metadata b/synth.metadata index 509cf11..47ab579 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/python-analytics-data.git", - "sha": "8fd57a340b7e052dc9c4d6c33882add75405eb8b" + "sha": "e7fa3bd5817a51e852b47c427f598ef02f935437" } }, { @@ -19,14 +19,14 @@ "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "2c54c473779ea731128cea61a3a6c975a08a5378" + "sha": "eda422b90c3dde4a872a13e6b78a8f802c40d0db" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "2c54c473779ea731128cea61a3a6c975a08a5378" + "sha": "eda422b90c3dde4a872a13e6b78a8f802c40d0db" } } ], From ad51cf28f6c3e306780ca48eb26299b4158068ad Mon Sep 17 00:00:00 2001 From: ikuleshov Date: Fri, 19 Mar 2021 13:44:18 -0700 Subject: [PATCH 2/8] docs: update quickstart samples to support the Data API v1 beta (#50) * docs: added a sample * docs: usage instructions updated to use Python3 * docs: updated sample to include main() method * docs: update the sample to support the Google Analytics Data API v1 beta * docs: update quickstart samples to support the Data API v1 beta * docs: update quickstart samples to support the Data API v1 beta * separate the sample into separate methods to facilitate testing * separate the sample into separate methods to facilitate testing * fix: update formatting * fix: update formatting * add noxfile_config with a test property id value * add noxfile_config with a test property id value * fix: use the credentials json file provided during the test * fix: use the credentials json file provided during the test --- samples/snippets/noxfile_config.py | 16 +++ samples/snippets/quickstart.py | 101 ++++++------------ .../snippets/quickstart_json_credentials.py | 72 +++++++++++++ .../quickstart_json_credentials_test.py | 29 +++++ samples/snippets/quickstart_oauth2.py | 89 +++++++++++++++ samples/snippets/quickstart_oauth2_test.py | 24 +++++ samples/snippets/quickstart_test.py | 4 +- samples/snippets/requirements.txt | 1 + 8 files changed, 269 insertions(+), 67 deletions(-) create mode 100644 samples/snippets/noxfile_config.py create mode 100644 samples/snippets/quickstart_json_credentials.py create mode 100644 samples/snippets/quickstart_json_credentials_test.py create mode 100644 samples/snippets/quickstart_oauth2.py create mode 100644 samples/snippets/quickstart_oauth2_test.py diff --git a/samples/snippets/noxfile_config.py b/samples/snippets/noxfile_config.py new file mode 100644 index 0000000..20c30ee --- /dev/null +++ b/samples/snippets/noxfile_config.py @@ -0,0 +1,16 @@ +TEST_CONFIG_OVERRIDE = { + # You can opt out from the test for specific Python versions. + "ignored_versions": ["2.7"], + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + "enforce_type_hints": True, + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + "envs": {"GA_TEST_PROPERTY_ID": "222596558"}, +} diff --git a/samples/snippets/quickstart.py b/samples/snippets/quickstart.py index 5c6657d..c3fe192 100644 --- a/samples/snippets/quickstart.py +++ b/samples/snippets/quickstart.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright 2020 Google Inc. All Rights Reserved. +# Copyright 2021 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,87 +15,56 @@ # limitations under the License. """Google Analytics Data API sample quickstart application. -Example usage: - python quickstart.py --property_id - - where is the Google Analytics property id to use for a query. - -Note: you need to have the Google Analytics Data API enabled in your project -prior to running this sample. Please visit the following URL and make sure the -API is enabled: - -https://console.developers.google.com/apis/library/analyticsdata.googleapis.com This application demonstrates the usage of the Analytics Data API using -service account credentials. For more information on service accounts, see - -https://cloud.google.com/iam/docs/understanding-service-accounts - -The following document provides instructions on setting service account -credentials for your application: - - https://cloud.google.com/docs/authentication/production - -In a nutshell, you need to: -1. Create a service account and download the key JSON file. - -https://cloud.google.com/docs/authentication/production#creating_a_service_account +service account credentials. -2. Provide service account credentials using one of the following options: -- set the GOOGLE_APPLICATION_CREDENTIALS environment variable, the API -client will use the value of this variable to find the service account key -JSON file. +Before you start the application, please review the comments starting with +"TODO(developer)" and update the code to use correct values. -https://cloud.google.com/docs/authentication/production#setting_the_environment_variable - -OR -- manually pass the path to the service account key JSON file to the API client -by specifying the keyFilename parameter in the constructor: -https://cloud.google.com/docs/authentication/production#passing_the_path_to_the_service_account_key_in_code - -To install the latest published package dependency, execute the following: - pip install google-analytics-data +Usage: + pip3 install --upgrade google-analytics-data + python3 quickstart.py """ -import argparse +# [START google_analytics_data_quickstart] +from google.analytics.data_v1beta import BetaAnalyticsDataClient +from google.analytics.data_v1beta.types import DateRange +from google.analytics.data_v1beta.types import Dimension +from google.analytics.data_v1beta.types import Metric +from google.analytics.data_v1beta.types import RunReportRequest -# [START ga_data_run_report] -from google.analytics.data_v1alpha import AlphaAnalyticsDataClient -from google.analytics.data_v1alpha.types import DateRange -from google.analytics.data_v1alpha.types import Dimension -from google.analytics.data_v1alpha.types import Entity -from google.analytics.data_v1alpha.types import Metric -from google.analytics.data_v1alpha.types import RunReportRequest +def sample_run_report(property_id="YOUR-GA4-PROPERTY-ID"): + """Runs a simple report on a Google Analytics 4 property.""" + # TODO(developer): Uncomment this variable and replace with your + # Google Analytics 4 property ID before running the sample. + # property_id = "YOUR-GA4-PROPERTY-ID" -def sample_run_report(property_id): - """Runs a simple report on a Google Analytics App+Web property.""" - + # [START google_analytics_data_initialize] # Using a default constructor instructs the client to use the credentials # specified in GOOGLE_APPLICATION_CREDENTIALS environment variable. - client = AlphaAnalyticsDataClient() - request = RunReportRequest(entity=Entity(property_id=property_id), - dimensions=[Dimension(name='city')], - metrics=[Metric(name='activeUsers')], - date_ranges=[DateRange(start_date='2020-03-31', - end_date='today')]) + client = BetaAnalyticsDataClient() + # [END google_analytics_data_initialize] + + # [START google_analytics_data_run_report] + request = RunReportRequest( + property="properties/" + str(property_id), + dimensions=[Dimension(name="city")], + metrics=[Metric(name="activeUsers")], + date_ranges=[DateRange(start_date="2020-03-31", end_date="today")], + ) response = client.run_report(request) + # [END google_analytics_data_run_report] + # [START google_analytics_data_run_report_response] print("Report result:") for row in response.rows: print(row.dimension_values[0].value, row.metric_values[0].value) + # [END google_analytics_data_run_report_response] -# [END ga_data_run_report] +# [END google_analytics_data_quickstart] + if __name__ == "__main__": - parser = argparse.ArgumentParser( - description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, - ) - parser.add_argument( - "--property_id", - type=str, - required=True, - help="Google Analytics property ID to use for a query.", - ) - args = parser.parse_args() - sample_run_report(args.property_id) + sample_run_report() diff --git a/samples/snippets/quickstart_json_credentials.py b/samples/snippets/quickstart_json_credentials.py new file mode 100644 index 0000000..97b9b4f --- /dev/null +++ b/samples/snippets/quickstart_json_credentials.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +# Copyright 2021 Google Inc. All Rights Reserved. +# +# 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. + +"""Google Analytics Data API sample quickstart application. + +This application demonstrates the usage of the Analytics Data API using +service account credentials from a JSON file downloaded from +the Google Cloud Console. + +Before you start the application, please review the comments starting with +"TODO(developer)" and update the code to use correct values. + +Usage: + pip3 install --upgrade google-analytics-data + python3 quickstart_json_credentials.py +""" +# [START google_analytics_data_quickstart] +from google.analytics.data_v1beta import BetaAnalyticsDataClient +from google.analytics.data_v1beta.types import DateRange +from google.analytics.data_v1beta.types import Dimension +from google.analytics.data_v1beta.types import Metric +from google.analytics.data_v1beta.types import RunReportRequest + + +def sample_run_report(property_id="YOUR-GA4-PROPERTY-ID", credentials_json_path=""): + """Runs a simple report on a Google Analytics 4 property.""" + # TODO(developer): Uncomment this variable and replace with your + # Google Analytics 4 property ID before running the sample. + # property_id = "YOUR-GA4-PROPERTY-ID" + + # [START google_analytics_data_initialize] + # TODO(developer): Uncomment this variable and replace with a valid path to + # the credentials.json file for your service account downloaded from the + # Cloud Console. + # credentials_json_path = "/path/to/credentials.json" + + # Explicitly use service account credentials by specifying + # the private key file. + client = BetaAnalyticsDataClient().from_service_account_json(credentials_json_path) + # [END google_analytics_data_initialize] + + # [START google_analytics_data_run_report] + request = RunReportRequest( + property="properties/" + str(property_id), + dimensions=[Dimension(name="city")], + metrics=[Metric(name="activeUsers")], + date_ranges=[DateRange(start_date="2020-03-31", end_date="today")], + ) + response = client.run_report(request) + # [END google_analytics_data_run_report] + + print("Report result:") + for row in response.rows: + print(row.dimension_values[0].value, row.metric_values[0].value) +# [END google_analytics_data_quickstart] + + +if __name__ == "__main__": + sample_run_report() diff --git a/samples/snippets/quickstart_json_credentials_test.py b/samples/snippets/quickstart_json_credentials_test.py new file mode 100644 index 0000000..06d7d1e --- /dev/null +++ b/samples/snippets/quickstart_json_credentials_test.py @@ -0,0 +1,29 @@ +# Copyright 2020 Google Inc. All Rights Reserved. +# +# 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 os + +import quickstart_json_credentials + + +def test_quickstart(capsys): + # Create a temporary service account credentials JSON file to be used by + # the test. + TEST_PROPERTY_ID = os.getenv("GA_TEST_PROPERTY_ID") + CREDENTIALS_JSON_PATH = os.getenv("GOOGLE_APPLICATION_CREDENTIALS") + quickstart_json_credentials.sample_run_report( + TEST_PROPERTY_ID, CREDENTIALS_JSON_PATH + ) + out, _ = capsys.readouterr() + assert "Report result" in out diff --git a/samples/snippets/quickstart_oauth2.py b/samples/snippets/quickstart_oauth2.py new file mode 100644 index 0000000..4ef3228 --- /dev/null +++ b/samples/snippets/quickstart_oauth2.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +# Copyright 2021 Google Inc. All Rights Reserved. +# +# 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. + +"""Google Analytics Data API sample quickstart application. + +This application demonstrates the usage of the Analytics Data API using +OAuth2 credentials. + +Before you start the application, please review the comments starting with +"TODO(developer)" and update the code to use correct values. + +Usage: + pip3 install --upgrade google-auth-oauthlib + pip3 install --upgrade google-analytics-data + python3 quickstart_oauth2.py +""" +# [START google_analytics_data_quickstart] +from google.analytics.data import BetaAnalyticsDataClient +from google.analytics.data_v1beta.types import DateRange +from google.analytics.data_v1beta.types import Dimension +from google.analytics.data_v1beta.types import Metric +from google.analytics.data_v1beta.types import RunReportRequest +from google_auth_oauthlib import flow + + +def sample_run_report(credentials=None, property_id="YOUR-GA4-PROPERTY-ID"): + """Runs a simple report on a Google Analytics 4 property.""" + # TODO(developer): Uncomment this variable and replace with your + # Google Analytics 4 property ID before running the sample. + # property_id = "YOUR-GA4-PROPERTY-ID" + + client = BetaAnalyticsDataClient(credentials=credentials) + request = RunReportRequest( + property="properties/" + str(property_id), + dimensions=[Dimension(name="city")], + metrics=[Metric(name="activeUsers")], + date_ranges=[DateRange(start_date="2020-03-31", end_date="today")], + ) + + response = client.run_report(request) + + print("Report result:") + for row in response.rows: + print(row.dimension_values[0].value, row.metric_values[0].value) + + +def get_credentials(): + """Creates an OAuth2 credentials instance.""" + # [START google_analytics_data_initialize] + appflow = flow.InstalledAppFlow.from_client_secrets_file( + "client_secrets.json", + scopes=["https://www.googleapis.com/auth/analytics.readonly"], + ) + # TODO(developer): Update the line below to set the `launch_browser` variable. + # The `launch_browser` boolean variable indicates if a local server is used + # as the callback URL in the auth flow. A value of `True` is recommended, + # but a local server does not work if accessing the application remotely, + # such as over SSH or from a remote Jupyter notebook. + launch_browser = True + if launch_browser: + appflow.run_local_server() + else: + appflow.run_console() + return appflow.credentials + # [END google_analytics_data_initialize] + + +def main(): + credentials = get_credentials() + sample_run_report(credentials) + + +# [END google_analytics_data_quickstart] + +if __name__ == "__main__": + main() diff --git a/samples/snippets/quickstart_oauth2_test.py b/samples/snippets/quickstart_oauth2_test.py new file mode 100644 index 0000000..dcbdc19 --- /dev/null +++ b/samples/snippets/quickstart_oauth2_test.py @@ -0,0 +1,24 @@ +# Copyright 2020 Google Inc. All Rights Reserved. +# +# 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 os + +import quickstart_oauth2 + + +def test_quickstart(capsys): + TEST_PROPERTY_ID = os.getenv("GA_TEST_PROPERTY_ID") + quickstart_oauth2.sample_run_report(None, TEST_PROPERTY_ID) + out, _ = capsys.readouterr() + assert "Report result" in out diff --git a/samples/snippets/quickstart_test.py b/samples/snippets/quickstart_test.py index 7e1d307..14c639d 100644 --- a/samples/snippets/quickstart_test.py +++ b/samples/snippets/quickstart_test.py @@ -12,11 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os + import quickstart def test_quickstart(capsys): - TEST_PROPERTY_ID = '222596558' + TEST_PROPERTY_ID = os.getenv("GA_TEST_PROPERTY_ID") quickstart.sample_run_report(TEST_PROPERTY_ID) out, _ = capsys.readouterr() assert "Report result" in out diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index fcb2cda..e3b1250 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1 +1,2 @@ google-analytics-data==0.4.0 +google-auth-oauthlib==0.4.3 \ No newline at end of file From c5de6551e5f7cfa96c81cf6a2bab9f46c240a5ee Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Tue, 23 Mar 2021 08:02:51 -0700 Subject: [PATCH 3/8] chore: upgrade gapic-generator-python to 0.43.1 (#54) PiperOrigin-RevId: 364411656 Source-Author: Google APIs Source-Date: Mon Mar 22 14:40:22 2021 -0700 Source-Repo: googleapis/googleapis Source-Sha: 149a3a84c29c9b8189576c7442ccb6dcf6a8f95b Source-Link: https://github.com/googleapis/googleapis/commit/149a3a84c29c9b8189576c7442ccb6dcf6a8f95b --- .../alpha_analytics_data/transports/base.py | 18 +-- .../alpha_analytics_data/transports/grpc.py | 101 ++++++---------- .../transports/grpc_asyncio.py | 109 +++++++----------- .../beta_analytics_data/transports/base.py | 18 +-- .../beta_analytics_data/transports/grpc.py | 101 ++++++---------- .../transports/grpc_asyncio.py | 109 +++++++----------- synth.metadata | 6 +- 7 files changed, 177 insertions(+), 285 deletions(-) diff --git a/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/base.py b/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/base.py index 1aff5ca..f45d8d2 100644 --- a/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/base.py +++ b/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/base.py @@ -70,10 +70,10 @@ def __init__( scope (Optional[Sequence[str]]): A list of scopes. quota_project_id (Optional[str]): An optional project to use for billing and quota. - client_info (google.api_core.gapic_v1.client_info.ClientInfo): - The client info used to send a user-agent string along with - API requests. If ``None``, then default info will be used. - Generally, you only need to set this if you're developing + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing your own client library. """ # Save the hostname. Default to port 443 (HTTPS) if none is specified. @@ -81,6 +81,9 @@ def __init__( host += ":443" self._host = host + # Save the scopes. + self._scopes = scopes or self.AUTH_SCOPES + # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: @@ -90,20 +93,17 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials - # Lifted into its own function so it can be stubbed out during tests. - self._prep_wrapped_messages(client_info) - def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { diff --git a/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/grpc.py b/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/grpc.py index 911aea5..5a08f8f 100644 --- a/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/grpc.py +++ b/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/grpc.py @@ -106,7 +106,9 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} if api_mtls_endpoint: warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) @@ -114,70 +116,50 @@ def __init__( warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) - else: - ssl_credentials = SslCredentials().ssl_credentials - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials else: - host = host if ":" in host else host + ":443" + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if client_cert_source_for_mtls and not ssl_channel_credentials: - cert, key = client_cert_source_for_mtls() - self._ssl_channel_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, + scopes=self._scopes, ssl_credentials=self._ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -185,17 +167,8 @@ def __init__( ], ) - self._stubs = {} # type: Dict[str, Callable] - - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -209,7 +182,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If diff --git a/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/grpc_asyncio.py b/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/grpc_asyncio.py index 15f4013..031af21 100644 --- a/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/grpc_asyncio.py +++ b/google/analytics/data_v1alpha/services/alpha_analytics_data/transports/grpc_asyncio.py @@ -61,7 +61,7 @@ def create_channel( ) -> aio.Channel: """Create and return a gRPC AsyncIO channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If @@ -139,10 +139,10 @@ def __init__( ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. - client_info (google.api_core.gapic_v1.client_info.ClientInfo): - The client info used to send a user-agent string along with - API requests. If ``None``, then default info will be used. - Generally, you only need to set this if you're developing + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing your own client library. Raises: @@ -151,7 +151,9 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} if api_mtls_endpoint: warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) @@ -159,70 +161,50 @@ def __init__( warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) - else: - ssl_credentials = SslCredentials().ssl_credentials - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials else: - host = host if ":" in host else host + ":443" + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if client_cert_source_for_mtls and not ssl_channel_credentials: - cert, key = client_cert_source_for_mtls() - self._ssl_channel_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, + scopes=self._scopes, ssl_credentials=self._ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -230,17 +212,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: 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 430c9dc..a2d0d7d 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 @@ -70,10 +70,10 @@ def __init__( scope (Optional[Sequence[str]]): A list of scopes. quota_project_id (Optional[str]): An optional project to use for billing and quota. - client_info (google.api_core.gapic_v1.client_info.ClientInfo): - The client info used to send a user-agent string along with - API requests. If ``None``, then default info will be used. - Generally, you only need to set this if you're developing + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing your own client library. """ # Save the hostname. Default to port 443 (HTTPS) if none is specified. @@ -81,6 +81,9 @@ def __init__( host += ":443" self._host = host + # Save the scopes. + self._scopes = scopes or self.AUTH_SCOPES + # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: @@ -90,20 +93,17 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials - # Lifted into its own function so it can be stubbed out during tests. - self._prep_wrapped_messages(client_info) - def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { 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 c2ebac2..d744160 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 @@ -106,7 +106,9 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} if api_mtls_endpoint: warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) @@ -114,70 +116,50 @@ def __init__( warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) - else: - ssl_credentials = SslCredentials().ssl_credentials - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials else: - host = host if ":" in host else host + ":443" + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if client_cert_source_for_mtls and not ssl_channel_credentials: - cert, key = client_cert_source_for_mtls() - self._ssl_channel_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, + scopes=self._scopes, ssl_credentials=self._ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -185,17 +167,8 @@ def __init__( ], ) - self._stubs = {} # type: Dict[str, Callable] - - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -209,7 +182,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If 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 dcf5965..09c2015 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 @@ -61,7 +61,7 @@ def create_channel( ) -> aio.Channel: """Create and return a gRPC AsyncIO channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If @@ -139,10 +139,10 @@ def __init__( ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. - client_info (google.api_core.gapic_v1.client_info.ClientInfo): - The client info used to send a user-agent string along with - API requests. If ``None``, then default info will be used. - Generally, you only need to set this if you're developing + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing your own client library. Raises: @@ -151,7 +151,9 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} if api_mtls_endpoint: warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) @@ -159,70 +161,50 @@ def __init__( warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) - else: - ssl_credentials = SslCredentials().ssl_credentials - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials else: - host = host if ":" in host else host + ":443" + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if client_cert_source_for_mtls and not ssl_channel_credentials: - cert, key = client_cert_source_for_mtls() - self._ssl_channel_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, + scopes=self._scopes, ssl_credentials=self._ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -230,17 +212,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: diff --git a/synth.metadata b/synth.metadata index 47ab579..7fea030 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,15 +4,15 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/python-analytics-data.git", - "sha": "e7fa3bd5817a51e852b47c427f598ef02f935437" + "sha": "ad51cf28f6c3e306780ca48eb26299b4158068ad" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "28a591963253d52ce3a25a918cafbdd9928de8cf", - "internalRef": "361662015" + "sha": "149a3a84c29c9b8189576c7442ccb6dcf6a8f95b", + "internalRef": "364411656" } }, { From 4551e9951679e1b82f2fd8c581cb024d80099dbe Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Tue, 23 Mar 2021 12:34:11 -0700 Subject: [PATCH 4/8] chore(python): add kokoro configs for periodic builds against head (#53) This change should be non-destructive. Note for library repo maintainers: After applying this change, you can easily add (or change) periodic builds against head by adding config files in google3. See python-pubsub repo for example. Source-Author: Takashi Matsuo Source-Date: Fri Mar 19 11:17:59 2021 -0700 Source-Repo: googleapis/synthtool Source-Sha: 79c8dd7ee768292f933012d3a69a5b4676404cda Source-Link: https://github.com/googleapis/synthtool/commit/79c8dd7ee768292f933012d3a69a5b4676404cda --- .kokoro/samples/python3.6/periodic-head.cfg | 11 +++ .kokoro/samples/python3.7/periodic-head.cfg | 11 +++ .kokoro/samples/python3.8/periodic-head.cfg | 11 +++ .kokoro/test-samples-against-head.sh | 28 ++++++ .kokoro/test-samples-impl.sh | 102 ++++++++++++++++++++ .kokoro/test-samples.sh | 96 +++--------------- synth.metadata | 9 +- 7 files changed, 186 insertions(+), 82 deletions(-) create mode 100644 .kokoro/samples/python3.6/periodic-head.cfg create mode 100644 .kokoro/samples/python3.7/periodic-head.cfg create mode 100644 .kokoro/samples/python3.8/periodic-head.cfg create mode 100755 .kokoro/test-samples-against-head.sh create mode 100755 .kokoro/test-samples-impl.sh diff --git a/.kokoro/samples/python3.6/periodic-head.cfg b/.kokoro/samples/python3.6/periodic-head.cfg new file mode 100644 index 0000000..f9cfcd3 --- /dev/null +++ b/.kokoro/samples/python3.6/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/samples/python3.7/periodic-head.cfg b/.kokoro/samples/python3.7/periodic-head.cfg new file mode 100644 index 0000000..f9cfcd3 --- /dev/null +++ b/.kokoro/samples/python3.7/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/samples/python3.8/periodic-head.cfg b/.kokoro/samples/python3.8/periodic-head.cfg new file mode 100644 index 0000000..f9cfcd3 --- /dev/null +++ b/.kokoro/samples/python3.8/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/test-samples-against-head.sh b/.kokoro/test-samples-against-head.sh new file mode 100755 index 0000000..9612d03 --- /dev/null +++ b/.kokoro/test-samples-against-head.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright 2020 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 +# +# https://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. + +# A customized test runner for samples. +# +# For periodic builds, you can specify this file for testing against head. + +# `-e` enables the script to automatically fail when a command fails +# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero +set -eo pipefail +# Enables `**` to include files nested inside sub-folders +shopt -s globstar + +cd github/python-analytics-data + +exec .kokoro/test-samples-impl.sh diff --git a/.kokoro/test-samples-impl.sh b/.kokoro/test-samples-impl.sh new file mode 100755 index 0000000..cf5de74 --- /dev/null +++ b/.kokoro/test-samples-impl.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# Copyright 2021 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 +# +# https://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. + + +# `-e` enables the script to automatically fail when a command fails +# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero +set -eo pipefail +# Enables `**` to include files nested inside sub-folders +shopt -s globstar + +# Exit early if samples directory doesn't exist +if [ ! -d "./samples" ]; then + echo "No tests run. `./samples` not found" + exit 0 +fi + +# Disable buffering, so that the logs stream through. +export PYTHONUNBUFFERED=1 + +# Debug: show build environment +env | grep KOKORO + +# Install nox +python3.6 -m pip install --upgrade --quiet nox + +# Use secrets acessor service account to get secrets +if [[ -f "${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" ]]; then + gcloud auth activate-service-account \ + --key-file="${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" \ + --project="cloud-devrel-kokoro-resources" +fi + +# This script will create 3 files: +# - testing/test-env.sh +# - testing/service-account.json +# - testing/client-secrets.json +./scripts/decrypt-secrets.sh + +source ./testing/test-env.sh +export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/testing/service-account.json + +# For cloud-run session, we activate the service account for gcloud sdk. +gcloud auth activate-service-account \ + --key-file "${GOOGLE_APPLICATION_CREDENTIALS}" + +export GOOGLE_CLIENT_SECRETS=$(pwd)/testing/client-secrets.json + +echo -e "\n******************** TESTING PROJECTS ********************" + +# Switch to 'fail at end' to allow all tests to complete before exiting. +set +e +# Use RTN to return a non-zero value if the test fails. +RTN=0 +ROOT=$(pwd) +# Find all requirements.txt in the samples directory (may break on whitespace). +for file in samples/**/requirements.txt; do + cd "$ROOT" + # Navigate to the project folder. + file=$(dirname "$file") + cd "$file" + + echo "------------------------------------------------------------" + echo "- testing $file" + echo "------------------------------------------------------------" + + # Use nox to execute the tests for the project. + python3.6 -m nox -s "$RUN_TESTS_SESSION" + EXIT=$? + + # If this is a periodic build, send the test log to the FlakyBot. + # See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. + if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then + chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot + $KOKORO_GFILE_DIR/linux_amd64/flakybot + fi + + if [[ $EXIT -ne 0 ]]; then + RTN=1 + echo -e "\n Testing failed: Nox returned a non-zero exit code. \n" + else + echo -e "\n Testing completed.\n" + fi + +done +cd "$ROOT" + +# Workaround for Kokoro permissions issue: delete secrets +rm testing/{test-env.sh,client-secrets.json,service-account.json} + +exit "$RTN" diff --git a/.kokoro/test-samples.sh b/.kokoro/test-samples.sh index 7c04433..856e09d 100755 --- a/.kokoro/test-samples.sh +++ b/.kokoro/test-samples.sh @@ -13,6 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +# The default test runner for samples. +# +# For periodic builds, we rewinds the repo to the latest release, and +# run test-samples-impl.sh. # `-e` enables the script to automatically fail when a command fails # `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero @@ -24,87 +28,19 @@ cd github/python-analytics-data # Run periodic samples tests at latest release if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then + # preserving the test runner implementation. + cp .kokoro/test-samples-impl.sh "${TMPDIR}/test-samples-impl.sh" + echo "--- IMPORTANT IMPORTANT IMPORTANT ---" + echo "Now we rewind the repo back to the latest release..." LATEST_RELEASE=$(git describe --abbrev=0 --tags) git checkout $LATEST_RELEASE -fi - -# Exit early if samples directory doesn't exist -if [ ! -d "./samples" ]; then - echo "No tests run. `./samples` not found" - exit 0 -fi - -# Disable buffering, so that the logs stream through. -export PYTHONUNBUFFERED=1 - -# Debug: show build environment -env | grep KOKORO - -# Install nox -python3.6 -m pip install --upgrade --quiet nox - -# Use secrets acessor service account to get secrets -if [[ -f "${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" ]]; then - gcloud auth activate-service-account \ - --key-file="${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" \ - --project="cloud-devrel-kokoro-resources" -fi - -# This script will create 3 files: -# - testing/test-env.sh -# - testing/service-account.json -# - testing/client-secrets.json -./scripts/decrypt-secrets.sh - -source ./testing/test-env.sh -export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/testing/service-account.json - -# For cloud-run session, we activate the service account for gcloud sdk. -gcloud auth activate-service-account \ - --key-file "${GOOGLE_APPLICATION_CREDENTIALS}" - -export GOOGLE_CLIENT_SECRETS=$(pwd)/testing/client-secrets.json - -echo -e "\n******************** TESTING PROJECTS ********************" - -# Switch to 'fail at end' to allow all tests to complete before exiting. -set +e -# Use RTN to return a non-zero value if the test fails. -RTN=0 -ROOT=$(pwd) -# Find all requirements.txt in the samples directory (may break on whitespace). -for file in samples/**/requirements.txt; do - cd "$ROOT" - # Navigate to the project folder. - file=$(dirname "$file") - cd "$file" - - echo "------------------------------------------------------------" - echo "- testing $file" - echo "------------------------------------------------------------" - - # Use nox to execute the tests for the project. - python3.6 -m nox -s "$RUN_TESTS_SESSION" - EXIT=$? - - # If this is a periodic build, send the test log to the FlakyBot. - # See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. - if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then - chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot - $KOKORO_GFILE_DIR/linux_amd64/flakybot + echo "The current head is: " + echo $(git rev-parse --verify HEAD) + echo "--- IMPORTANT IMPORTANT IMPORTANT ---" + # move back the test runner implementation if there's no file. + if [ ! -f .kokoro/test-samples-impl.sh ]; then + cp "${TMPDIR}/test-samples-impl.sh" .kokoro/test-samples-impl.sh fi +fi - if [[ $EXIT -ne 0 ]]; then - RTN=1 - echo -e "\n Testing failed: Nox returned a non-zero exit code. \n" - else - echo -e "\n Testing completed.\n" - fi - -done -cd "$ROOT" - -# Workaround for Kokoro permissions issue: delete secrets -rm testing/{test-env.sh,client-secrets.json,service-account.json} - -exit "$RTN" +exec .kokoro/test-samples-impl.sh diff --git a/synth.metadata b/synth.metadata index 7fea030..78be853 100644 --- a/synth.metadata +++ b/synth.metadata @@ -19,14 +19,14 @@ "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "eda422b90c3dde4a872a13e6b78a8f802c40d0db" + "sha": "79c8dd7ee768292f933012d3a69a5b4676404cda" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "eda422b90c3dde4a872a13e6b78a8f802c40d0db" + "sha": "79c8dd7ee768292f933012d3a69a5b4676404cda" } } ], @@ -83,16 +83,21 @@ ".kokoro/samples/lint/presubmit.cfg", ".kokoro/samples/python3.6/common.cfg", ".kokoro/samples/python3.6/continuous.cfg", + ".kokoro/samples/python3.6/periodic-head.cfg", ".kokoro/samples/python3.6/periodic.cfg", ".kokoro/samples/python3.6/presubmit.cfg", ".kokoro/samples/python3.7/common.cfg", ".kokoro/samples/python3.7/continuous.cfg", + ".kokoro/samples/python3.7/periodic-head.cfg", ".kokoro/samples/python3.7/periodic.cfg", ".kokoro/samples/python3.7/presubmit.cfg", ".kokoro/samples/python3.8/common.cfg", ".kokoro/samples/python3.8/continuous.cfg", + ".kokoro/samples/python3.8/periodic-head.cfg", ".kokoro/samples/python3.8/periodic.cfg", ".kokoro/samples/python3.8/presubmit.cfg", + ".kokoro/test-samples-against-head.sh", + ".kokoro/test-samples-impl.sh", ".kokoro/test-samples.sh", ".kokoro/trampoline.sh", ".kokoro/trampoline_v2.sh", From 747f551c4b3a2f5b3d4602788b8f9c19cbd9904b Mon Sep 17 00:00:00 2001 From: ikuleshov Date: Thu, 25 Mar 2021 12:23:10 -0700 Subject: [PATCH 5/8] docs: update region tag names to match the convention (#55) * docs: update region tag names to match the convention * lint --- samples/snippets/quickstart.py | 16 ++++++++-------- samples/snippets/quickstart_json_credentials.py | 14 ++++++++------ samples/snippets/quickstart_oauth2.py | 8 ++++---- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/samples/snippets/quickstart.py b/samples/snippets/quickstart.py index c3fe192..7572097 100644 --- a/samples/snippets/quickstart.py +++ b/samples/snippets/quickstart.py @@ -26,7 +26,7 @@ pip3 install --upgrade google-analytics-data python3 quickstart.py """ -# [START google_analytics_data_quickstart] +# [START analyticsdata_quickstart] from google.analytics.data_v1beta import BetaAnalyticsDataClient from google.analytics.data_v1beta.types import DateRange from google.analytics.data_v1beta.types import Dimension @@ -40,13 +40,13 @@ def sample_run_report(property_id="YOUR-GA4-PROPERTY-ID"): # Google Analytics 4 property ID before running the sample. # property_id = "YOUR-GA4-PROPERTY-ID" - # [START google_analytics_data_initialize] + # [START analyticsdata_run_report_initialize] # Using a default constructor instructs the client to use the credentials # specified in GOOGLE_APPLICATION_CREDENTIALS environment variable. client = BetaAnalyticsDataClient() - # [END google_analytics_data_initialize] + # [END analyticsdata_run_report_initialize] - # [START google_analytics_data_run_report] + # [START analyticsdata_run_report] request = RunReportRequest( property="properties/" + str(property_id), dimensions=[Dimension(name="city")], @@ -54,16 +54,16 @@ def sample_run_report(property_id="YOUR-GA4-PROPERTY-ID"): date_ranges=[DateRange(start_date="2020-03-31", end_date="today")], ) response = client.run_report(request) - # [END google_analytics_data_run_report] + # [END analyticsdata_run_report] - # [START google_analytics_data_run_report_response] + # [START analyticsdata_run_report_response] print("Report result:") for row in response.rows: print(row.dimension_values[0].value, row.metric_values[0].value) - # [END google_analytics_data_run_report_response] + # [END analyticsdata_run_report_response] -# [END google_analytics_data_quickstart] +# [END analyticsdata_quickstart] if __name__ == "__main__": diff --git a/samples/snippets/quickstart_json_credentials.py b/samples/snippets/quickstart_json_credentials.py index 97b9b4f..a30c8ea 100644 --- a/samples/snippets/quickstart_json_credentials.py +++ b/samples/snippets/quickstart_json_credentials.py @@ -27,7 +27,7 @@ pip3 install --upgrade google-analytics-data python3 quickstart_json_credentials.py """ -# [START google_analytics_data_quickstart] +# [START analyticsdata_json_credentials_quickstart] from google.analytics.data_v1beta import BetaAnalyticsDataClient from google.analytics.data_v1beta.types import DateRange from google.analytics.data_v1beta.types import Dimension @@ -41,7 +41,7 @@ def sample_run_report(property_id="YOUR-GA4-PROPERTY-ID", credentials_json_path= # Google Analytics 4 property ID before running the sample. # property_id = "YOUR-GA4-PROPERTY-ID" - # [START google_analytics_data_initialize] + # [START analyticsdata_json_credentials_initialize] # TODO(developer): Uncomment this variable and replace with a valid path to # the credentials.json file for your service account downloaded from the # Cloud Console. @@ -50,9 +50,9 @@ def sample_run_report(property_id="YOUR-GA4-PROPERTY-ID", credentials_json_path= # Explicitly use service account credentials by specifying # the private key file. client = BetaAnalyticsDataClient().from_service_account_json(credentials_json_path) - # [END google_analytics_data_initialize] + # [END analyticsdata_json_credentials_initialize] - # [START google_analytics_data_run_report] + # [START analyticsdata_json_credentials_run_report] request = RunReportRequest( property="properties/" + str(property_id), dimensions=[Dimension(name="city")], @@ -60,12 +60,14 @@ def sample_run_report(property_id="YOUR-GA4-PROPERTY-ID", credentials_json_path= date_ranges=[DateRange(start_date="2020-03-31", end_date="today")], ) response = client.run_report(request) - # [END google_analytics_data_run_report] + # [END analyticsdata_json_credentials_run_report] print("Report result:") for row in response.rows: print(row.dimension_values[0].value, row.metric_values[0].value) -# [END google_analytics_data_quickstart] + + +# [END analyticsdata_json_credentials_quickstart] if __name__ == "__main__": diff --git a/samples/snippets/quickstart_oauth2.py b/samples/snippets/quickstart_oauth2.py index 4ef3228..83aae0b 100644 --- a/samples/snippets/quickstart_oauth2.py +++ b/samples/snippets/quickstart_oauth2.py @@ -27,7 +27,7 @@ pip3 install --upgrade google-analytics-data python3 quickstart_oauth2.py """ -# [START google_analytics_data_quickstart] +# [START analyticsdata_quickstart_oauth2] from google.analytics.data import BetaAnalyticsDataClient from google.analytics.data_v1beta.types import DateRange from google.analytics.data_v1beta.types import Dimension @@ -59,7 +59,7 @@ def sample_run_report(credentials=None, property_id="YOUR-GA4-PROPERTY-ID"): def get_credentials(): """Creates an OAuth2 credentials instance.""" - # [START google_analytics_data_initialize] + # [START analyticsdata_initialize] appflow = flow.InstalledAppFlow.from_client_secrets_file( "client_secrets.json", scopes=["https://www.googleapis.com/auth/analytics.readonly"], @@ -75,7 +75,7 @@ def get_credentials(): else: appflow.run_console() return appflow.credentials - # [END google_analytics_data_initialize] + # [END analyticsdata_initialize] def main(): @@ -83,7 +83,7 @@ def main(): sample_run_report(credentials) -# [END google_analytics_data_quickstart] +# [END analyticsdata_quickstart_oauth2] if __name__ == "__main__": main() From 1c1d58f1ee88e50ce92c40b0ec58c19cec631297 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 30 Mar 2021 17:41:46 +0200 Subject: [PATCH 6/8] chore(deps): update dependency google-auth-oauthlib to v0.4.4 (#58) --- samples/snippets/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index e3b1250..4d222ea 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,2 +1,2 @@ google-analytics-data==0.4.0 -google-auth-oauthlib==0.4.3 \ No newline at end of file +google-auth-oauthlib==0.4.4 \ No newline at end of file From 83f1fc1af4baa799d3f457127ef2fe687b0aa49d Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Thu, 1 Apr 2021 11:31:52 -0700 Subject: [PATCH 7/8] feat: add `kind` field which is used to distinguish between response types (#60) feat: add `potentially_thresholded_requests_per_hour` field to `PropertyQuota` --- .../data_v1beta/types/analytics_data_api.py | 35 +++++++++++++ google/analytics/data_v1beta/types/data.py | 16 ++++-- synth.metadata | 6 +-- .../data_v1beta/test_beta_analytics_data.py | 52 +++++++++++++++---- 4 files changed, 93 insertions(+), 16 deletions(-) diff --git a/google/analytics/data_v1beta/types/analytics_data_api.py b/google/analytics/data_v1beta/types/analytics_data_api.py index 8f8a10b..ca14a44 100644 --- a/google/analytics/data_v1beta/types/analytics_data_api.py +++ b/google/analytics/data_v1beta/types/analytics_data_api.py @@ -220,6 +220,11 @@ class RunReportResponse(proto.Message): property_quota (google.analytics.data_v1beta.types.PropertyQuota): This Analytics Property's quota state including this request. + kind (str): + Identifies what kind of resource this message is. This + ``kind`` is always the fixed string + "analyticsData#runReport". Useful to distinguish between + response types in JSON. """ dimension_headers = proto.RepeatedField( @@ -244,6 +249,8 @@ class RunReportResponse(proto.Message): property_quota = proto.Field(proto.MESSAGE, number=9, message=data.PropertyQuota,) + kind = proto.Field(proto.STRING, number=10) + class RunPivotReportRequest(proto.Message): r"""The request to generate a pivot report. @@ -405,6 +412,11 @@ class RunPivotReportResponse(proto.Message): property_quota (google.analytics.data_v1beta.types.PropertyQuota): This Analytics Property's quota state including this request. + kind (str): + Identifies what kind of resource this message is. This + ``kind`` is always the fixed string + "analyticsData#runPivotReport". Useful to distinguish + between response types in JSON. """ pivot_headers = proto.RepeatedField( @@ -427,6 +439,8 @@ class RunPivotReportResponse(proto.Message): property_quota = proto.Field(proto.MESSAGE, number=7, message=data.PropertyQuota,) + kind = proto.Field(proto.STRING, number=8) + class BatchRunReportsRequest(proto.Message): r"""The batch request containing multiple report requests. @@ -460,10 +474,17 @@ class BatchRunReportsResponse(proto.Message): reports (Sequence[google.analytics.data_v1beta.types.RunReportResponse]): Individual responses. Each response has a separate report request. + kind (str): + Identifies what kind of resource this message is. This + ``kind`` is always the fixed string + "analyticsData#batchRunReports". Useful to distinguish + between response types in JSON. """ reports = proto.RepeatedField(proto.MESSAGE, number=1, message="RunReportResponse",) + kind = proto.Field(proto.STRING, number=2) + class BatchRunPivotReportsRequest(proto.Message): r"""The batch request containing multiple pivot report requests. @@ -499,12 +520,19 @@ class BatchRunPivotReportsResponse(proto.Message): pivot_reports (Sequence[google.analytics.data_v1beta.types.RunPivotReportResponse]): Individual responses. Each response has a separate pivot report request. + kind (str): + Identifies what kind of resource this message is. This + ``kind`` is always the fixed string + "analyticsData#batchRunPivotReports". Useful to distinguish + between response types in JSON. """ pivot_reports = proto.RepeatedField( proto.MESSAGE, number=1, message="RunPivotReportResponse", ) + kind = proto.Field(proto.STRING, number=2) + class GetMetadataRequest(proto.Message): r"""Request for a property's dimension and metric metadata. @@ -634,6 +662,11 @@ class RunRealtimeReportResponse(proto.Message): property_quota (google.analytics.data_v1beta.types.PropertyQuota): This Analytics Property's Realtime quota state including this request. + kind (str): + Identifies what kind of resource this message is. This + ``kind`` is always the fixed string + "analyticsData#runRealtimeReport". Useful to distinguish + between response types in JSON. """ dimension_headers = proto.RepeatedField( @@ -656,5 +689,7 @@ class RunRealtimeReportResponse(proto.Message): property_quota = proto.Field(proto.MESSAGE, number=8, message=data.PropertyQuota,) + kind = proto.Field(proto.STRING, number=9) + __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/analytics/data_v1beta/types/data.py b/google/analytics/data_v1beta/types/data.py index 1f0fa19..c2c3313 100644 --- a/google/analytics/data_v1beta/types/data.py +++ b/google/analytics/data_v1beta/types/data.py @@ -562,9 +562,8 @@ class Pivot(proto.Message): is counted as row 0. limit (int): The number of unique combinations of dimension values to - return in this pivot. If unspecified, up to 10,000 unique - combinations of dimension values are returned. ``limit`` - must be positive. + return in this pivot. The ``limit`` parameter is required. A + ``limit`` of 10,000 is common for single pivot requests. The product of the ``limit`` for each ``pivot`` in a ``RunPivotReportRequest`` must not exceed 100,000. For @@ -955,6 +954,13 @@ class PropertyQuota(proto.Message): per hour; Analytics 360 Properties and cloud project pairs can have up to 50 server errors per hour. + potentially_thresholded_requests_per_hour (google.analytics.data_v1beta.types.QuotaStatus): + Analytics Properties can send up to 120 + requests with potentially thresholded dimensions + per hour. In a batch request, each report + request is individually counted for this quota + if the request contains potentially thresholded + dimensions. """ tokens_per_day = proto.Field(proto.MESSAGE, number=1, message="QuotaStatus",) @@ -967,6 +973,10 @@ class PropertyQuota(proto.Message): proto.MESSAGE, number=4, message="QuotaStatus", ) + potentially_thresholded_requests_per_hour = proto.Field( + proto.MESSAGE, number=5, message="QuotaStatus", + ) + class QuotaStatus(proto.Message): r"""Current state for a particular quota group. diff --git a/synth.metadata b/synth.metadata index 78be853..1729cec 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,15 +4,15 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/python-analytics-data.git", - "sha": "ad51cf28f6c3e306780ca48eb26299b4158068ad" + "sha": "1c1d58f1ee88e50ce92c40b0ec58c19cec631297" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "149a3a84c29c9b8189576c7442ccb6dcf6a8f95b", - "internalRef": "364411656" + "sha": "95dd24960cf9f794ef583e59ad9f1fabe1c4a924", + "internalRef": "365882072" } }, { 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 810069d..4a75e3e 100644 --- a/tests/unit/gapic/data_v1beta/test_beta_analytics_data.py +++ b/tests/unit/gapic/data_v1beta/test_beta_analytics_data.py @@ -471,7 +471,9 @@ def test_run_report( # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.run_report), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = analytics_data_api.RunReportResponse(row_count=992,) + call.return_value = analytics_data_api.RunReportResponse( + row_count=992, kind="kind_value", + ) response = client.run_report(request) @@ -487,6 +489,8 @@ def test_run_report( assert response.row_count == 992 + assert response.kind == "kind_value" + def test_run_report_from_dict(): test_run_report(request_type=dict) @@ -524,7 +528,7 @@ async def test_run_report_async( with mock.patch.object(type(client.transport.run_report), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - analytics_data_api.RunReportResponse(row_count=992,) + analytics_data_api.RunReportResponse(row_count=992, kind="kind_value",) ) response = await client.run_report(request) @@ -540,6 +544,8 @@ async def test_run_report_async( assert response.row_count == 992 + assert response.kind == "kind_value" + @pytest.mark.asyncio async def test_run_report_async_from_dict(): @@ -613,7 +619,9 @@ def test_run_pivot_report( # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.run_pivot_report), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = analytics_data_api.RunPivotReportResponse() + call.return_value = analytics_data_api.RunPivotReportResponse( + kind="kind_value", + ) response = client.run_pivot_report(request) @@ -627,6 +635,8 @@ def test_run_pivot_report( assert isinstance(response, analytics_data_api.RunPivotReportResponse) + assert response.kind == "kind_value" + def test_run_pivot_report_from_dict(): test_run_pivot_report(request_type=dict) @@ -665,7 +675,7 @@ async def test_run_pivot_report_async( with mock.patch.object(type(client.transport.run_pivot_report), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - analytics_data_api.RunPivotReportResponse() + analytics_data_api.RunPivotReportResponse(kind="kind_value",) ) response = await client.run_pivot_report(request) @@ -679,6 +689,8 @@ async def test_run_pivot_report_async( # Establish that the response is the type that we expect. assert isinstance(response, analytics_data_api.RunPivotReportResponse) + assert response.kind == "kind_value" + @pytest.mark.asyncio async def test_run_pivot_report_async_from_dict(): @@ -754,7 +766,9 @@ def test_batch_run_reports( type(client.transport.batch_run_reports), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = analytics_data_api.BatchRunReportsResponse() + call.return_value = analytics_data_api.BatchRunReportsResponse( + kind="kind_value", + ) response = client.batch_run_reports(request) @@ -768,6 +782,8 @@ def test_batch_run_reports( assert isinstance(response, analytics_data_api.BatchRunReportsResponse) + assert response.kind == "kind_value" + def test_batch_run_reports_from_dict(): test_batch_run_reports(request_type=dict) @@ -810,7 +826,7 @@ async def test_batch_run_reports_async( ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - analytics_data_api.BatchRunReportsResponse() + analytics_data_api.BatchRunReportsResponse(kind="kind_value",) ) response = await client.batch_run_reports(request) @@ -824,6 +840,8 @@ async def test_batch_run_reports_async( # Establish that the response is the type that we expect. assert isinstance(response, analytics_data_api.BatchRunReportsResponse) + assert response.kind == "kind_value" + @pytest.mark.asyncio async def test_batch_run_reports_async_from_dict(): @@ -903,7 +921,9 @@ def test_batch_run_pivot_reports( type(client.transport.batch_run_pivot_reports), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = analytics_data_api.BatchRunPivotReportsResponse() + call.return_value = analytics_data_api.BatchRunPivotReportsResponse( + kind="kind_value", + ) response = client.batch_run_pivot_reports(request) @@ -917,6 +937,8 @@ def test_batch_run_pivot_reports( assert isinstance(response, analytics_data_api.BatchRunPivotReportsResponse) + assert response.kind == "kind_value" + def test_batch_run_pivot_reports_from_dict(): test_batch_run_pivot_reports(request_type=dict) @@ -959,7 +981,7 @@ async def test_batch_run_pivot_reports_async( ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - analytics_data_api.BatchRunPivotReportsResponse() + analytics_data_api.BatchRunPivotReportsResponse(kind="kind_value",) ) response = await client.batch_run_pivot_reports(request) @@ -973,6 +995,8 @@ async def test_batch_run_pivot_reports_async( # Establish that the response is the type that we expect. assert isinstance(response, analytics_data_api.BatchRunPivotReportsResponse) + assert response.kind == "kind_value" + @pytest.mark.asyncio async def test_batch_run_pivot_reports_async_from_dict(): @@ -1265,7 +1289,9 @@ def test_run_realtime_report( type(client.transport.run_realtime_report), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = analytics_data_api.RunRealtimeReportResponse(row_count=992,) + call.return_value = analytics_data_api.RunRealtimeReportResponse( + row_count=992, kind="kind_value", + ) response = client.run_realtime_report(request) @@ -1281,6 +1307,8 @@ def test_run_realtime_report( assert response.row_count == 992 + assert response.kind == "kind_value" + def test_run_realtime_report_from_dict(): test_run_realtime_report(request_type=dict) @@ -1323,7 +1351,9 @@ async def test_run_realtime_report_async( ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - analytics_data_api.RunRealtimeReportResponse(row_count=992,) + analytics_data_api.RunRealtimeReportResponse( + row_count=992, kind="kind_value", + ) ) response = await client.run_realtime_report(request) @@ -1339,6 +1369,8 @@ async def test_run_realtime_report_async( assert response.row_count == 992 + assert response.kind == "kind_value" + @pytest.mark.asyncio async def test_run_realtime_report_async_from_dict(): From 5445abb8fd3912ce6cb92a1e22c956c835ab0728 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 1 Apr 2021 12:37:31 -0600 Subject: [PATCH 8/8] chore: release 0.5.0 (#61) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- CHANGELOG.md | 14 ++++++++++++++ setup.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48d99fd..e15e9a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.5.0](https://www.github.com/googleapis/python-analytics-data/compare/v0.4.1...v0.5.0) (2021-04-01) + + +### Features + +* add `kind` field which is used to distinguish between response types ([#60](https://www.github.com/googleapis/python-analytics-data/issues/60)) ([83f1fc1](https://www.github.com/googleapis/python-analytics-data/commit/83f1fc1af4baa799d3f457127ef2fe687b0aa49d)) +* add `potentially_thresholded_requests_per_hour` field to `PropertyQuota` ([83f1fc1](https://www.github.com/googleapis/python-analytics-data/commit/83f1fc1af4baa799d3f457127ef2fe687b0aa49d)) + + +### Documentation + +* update quickstart samples to support the Data API v1 beta ([#50](https://www.github.com/googleapis/python-analytics-data/issues/50)) ([ad51cf2](https://www.github.com/googleapis/python-analytics-data/commit/ad51cf28f6c3e306780ca48eb26299b4158068ad)) +* update region tag names to match the convention ([#55](https://www.github.com/googleapis/python-analytics-data/issues/55)) ([747f551](https://www.github.com/googleapis/python-analytics-data/commit/747f551c4b3a2f5b3d4602788b8f9c19cbd9904b)) + ### [0.4.1](https://www.github.com/googleapis/python-analytics-data/compare/v0.4.0...v0.4.1) (2021-03-16) diff --git a/setup.py b/setup.py index 012b229..6e8c419 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ import os import setuptools # type: ignore -version = "0.4.1" +version = "0.5.0" package_root = os.path.abspath(os.path.dirname(__file__))