From 50f07f5e5984b9ba9ddfe71806e133cd39196808 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 1 Dec 2022 16:19:22 -0800 Subject: [PATCH 1/9] client should attach veneer headers to all calls --- google/cloud/logging_v2/client.py | 4 ++++ tests/unit/test_client.py | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/google/cloud/logging_v2/client.py b/google/cloud/logging_v2/client.py index 049737861..218eee095 100644 --- a/google/cloud/logging_v2/client.py +++ b/google/cloud/logging_v2/client.py @@ -137,6 +137,10 @@ def __init__( kw_args["api_endpoint"] = api_endpoint self._connection = Connection(self, **kw_args) + if client_info is None: + # if client info not passed in, use the discovered + # client info from _connection object + client_info = self._connection._client_info self._client_info = client_info self._client_options = client_options diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 1a31e9c0c..a5840e2ec 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -16,11 +16,13 @@ from datetime import datetime from datetime import timedelta from datetime import timezone +import re import unittest import mock +VENEER_HEADER_REGEX = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gccl\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') def _make_credentials(): import google.auth.credentials @@ -148,6 +150,31 @@ def make_api(client_obj): again = client.logging_api self.assertIs(again, api) + def test_veneer_grpc_headers(self): + creds = _make_credentials() + # ensure client info is set on client object + client = self._make_one(project=self.PROJECT, credentials=creds, _use_grpc=True) + self.assertIsNotNone(client._client_info) + user_agent_sorted = " ".join(sorted(client._client_info.to_user_agent().split(" "))) + self.assertTrue(VENEER_HEADER_REGEX.match(user_agent_sorted)) + # ensure client info is propagated to gapic wrapped methods + patch = mock.patch("google.api_core.gapic_v1.method.wrap_method") + with patch as gapic_mock: + api = client.logging_api + client_info = gapic_mock.call_args.kwargs["client_info"] + self.assertIsNotNone(client_info) + wrapped_user_agent_sorted = " ".join(sorted(client_info.to_user_agent().split(" "))) + self.assertTrue(VENEER_HEADER_REGEX.match(wrapped_user_agent_sorted)) + + def test_veneer_http_headers(self): + creds = _make_credentials() + patch = mock.patch("google.api_core.gapic_v1.method.wrap_method") + with patch as http_mock: + client = self._make_one(project=self.PROJECT, credentials=creds, _use_grpc=False) + user_agent = client._connection._client_info.to_user_agent() + user_agent_sorted = " ".join(sorted(user_agent.split(" "))) + self.assertTrue(VENEER_HEADER_REGEX.match(user_agent_sorted)) + def test_no_gapic_ctor(self): from google.cloud.logging_v2._http import _LoggingAPI From 428ec6837c57bcc3ab541ccfcfe775405dcf6a07 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 1 Dec 2022 17:10:53 -0800 Subject: [PATCH 2/9] test all services --- tests/unit/test_client.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index a5840e2ec..cd891cdab 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -160,11 +160,17 @@ def test_veneer_grpc_headers(self): # ensure client info is propagated to gapic wrapped methods patch = mock.patch("google.api_core.gapic_v1.method.wrap_method") with patch as gapic_mock: - api = client.logging_api - client_info = gapic_mock.call_args.kwargs["client_info"] - self.assertIsNotNone(client_info) - wrapped_user_agent_sorted = " ".join(sorted(client_info.to_user_agent().split(" "))) - self.assertTrue(VENEER_HEADER_REGEX.match(wrapped_user_agent_sorted)) + client.logging_api # initialize logging api + client.metrics_api # initialize metrics api + client.sinks_api # initialize sinks api + wrapped_call_list = gapic_mock.call_args_list + num_api_calls = 37 # expected number of distinct APIs in all gapic services (logging,metrics,sinks) + self.assertGreaterEqual(len(wrapped_call_list), num_api_calls, "unexpected number of APIs wrapped") + for call in wrapped_call_list: + client_info = call.kwargs["client_info"] + self.assertIsNotNone(client_info) + wrapped_user_agent_sorted = " ".join(sorted(client_info.to_user_agent().split(" "))) + self.assertTrue(VENEER_HEADER_REGEX.match(wrapped_user_agent_sorted)) def test_veneer_http_headers(self): creds = _make_credentials() From 09628f3a647df6bcee9c780875cdac2c17c9b72b Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 1 Dec 2022 17:40:22 -0800 Subject: [PATCH 3/9] added tests for gapic headers --- tests/unit/gapic/logging_v2/test_config_service_v2.py | 10 ++++++++++ tests/unit/gapic/logging_v2/test_logging_service_v2.py | 10 ++++++++++ tests/unit/gapic/logging_v2/test_metrics_service_v2.py | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/tests/unit/gapic/logging_v2/test_config_service_v2.py b/tests/unit/gapic/logging_v2/test_config_service_v2.py index be77714c0..cd5d52fdc 100644 --- a/tests/unit/gapic/logging_v2/test_config_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_config_service_v2.py @@ -98,6 +98,16 @@ def test__get_default_mtls_endpoint(): ConfigServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi ) +def test_config_default_client_info_headers(): + import re + import pkg_resources + # test that DEFAULT_CLIENT_INFO contains the expected gapic headers + # go/cloud-api-headers-2019 + gapic_header_regex = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') + detected_info = google.cloud.logging_v2.services.config_service_v2.transports.base.DEFAULT_CLIENT_INFO + assert detected_info is not None + detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" "))) + assert gapic_header_regex.match(detected_agent) @pytest.mark.parametrize( "client_class,transport_name", diff --git a/tests/unit/gapic/logging_v2/test_logging_service_v2.py b/tests/unit/gapic/logging_v2/test_logging_service_v2.py index 3a169cc9d..43f978ba1 100644 --- a/tests/unit/gapic/logging_v2/test_logging_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_logging_service_v2.py @@ -70,6 +70,16 @@ def modify_default_endpoint(client): else client.DEFAULT_ENDPOINT ) +def test_logging_default_client_info_headers(): + import re + import pkg_resources + # test that DEFAULT_CLIENT_INFO contains the expected gapic headers + # go/cloud-api-headers-2019 + gapic_header_regex = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') + detected_info = google.cloud.logging_v2.services.logging_service_v2.transports.base.DEFAULT_CLIENT_INFO + assert detected_info is not None + detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" "))) + assert gapic_header_regex.match(detected_agent) def test__get_default_mtls_endpoint(): api_endpoint = "example.googleapis.com" diff --git a/tests/unit/gapic/logging_v2/test_metrics_service_v2.py b/tests/unit/gapic/logging_v2/test_metrics_service_v2.py index 37726ba52..55b01b7d7 100644 --- a/tests/unit/gapic/logging_v2/test_metrics_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_metrics_service_v2.py @@ -98,6 +98,16 @@ def test__get_default_mtls_endpoint(): == non_googleapi ) +def test_metrics_default_client_info_headers(): + import re + import pkg_resources + # test that DEFAULT_CLIENT_INFO contains the expected gapic headers + # go/cloud-api-headers-2019 + gapic_header_regex = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') + detected_info = google.cloud.logging_v2.services.metrics_service_v2.transports.base.DEFAULT_CLIENT_INFO + assert detected_info is not None + detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" "))) + assert gapic_header_regex.match(detected_agent) @pytest.mark.parametrize( "client_class,transport_name", From ef26b7990c495af92894cac71ae5a60d53f50dfa Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 1 Dec 2022 17:44:33 -0800 Subject: [PATCH 4/9] added comments, improved http test --- tests/unit/test_client.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index cd891cdab..618ef9b36 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -151,6 +151,9 @@ def make_api(client_obj): self.assertIs(again, api) def test_veneer_grpc_headers(self): + # test that client APIs have client_info populated with the expected veneer headers + # required for proper instrumentation + # go/cloud-api-headers-2019 creds = _make_credentials() # ensure client info is set on client object client = self._make_one(project=self.PROJECT, credentials=creds, _use_grpc=True) @@ -173,13 +176,20 @@ def test_veneer_grpc_headers(self): self.assertTrue(VENEER_HEADER_REGEX.match(wrapped_user_agent_sorted)) def test_veneer_http_headers(self): + # test that http APIs have client_info populated with the expected veneer headers + # required for proper instrumentation + # go/cloud-api-headers-2019 creds = _make_credentials() - patch = mock.patch("google.api_core.gapic_v1.method.wrap_method") - with patch as http_mock: - client = self._make_one(project=self.PROJECT, credentials=creds, _use_grpc=False) - user_agent = client._connection._client_info.to_user_agent() - user_agent_sorted = " ".join(sorted(user_agent.split(" "))) - self.assertTrue(VENEER_HEADER_REGEX.match(user_agent_sorted)) + # ensure client info is set on client object + client = self._make_one(project=self.PROJECT, credentials=creds, _use_grpc=False) + self.assertIsNotNone(client._client_info) + user_agent_sorted = " ".join(sorted(client._client_info.to_user_agent().split(" "))) + self.assertTrue(VENEER_HEADER_REGEX.match(user_agent_sorted)) + # ensure client info is propagated to _connection object + connection_user_agent = client._connection._client_info.to_user_agent() + self.assertIsNotNone(connection_user_agent) + connection_user_agent_sorted = " ".join(sorted(connection_user_agent.split(" "))) + self.assertTrue(VENEER_HEADER_REGEX.match(connection_user_agent_sorted)) def test_no_gapic_ctor(self): from google.cloud.logging_v2._http import _LoggingAPI From 9394c1c2d7710e4c67a2c731119d811b57a2775b Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Fri, 2 Dec 2022 01:55:09 +0000 Subject: [PATCH 5/9] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20po?= =?UTF-8?q?st-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- .../logging_v2/test_config_service_v2.py | 11 +++++- .../logging_v2/test_logging_service_v2.py | 11 +++++- .../logging_v2/test_metrics_service_v2.py | 11 +++++- tests/unit/test_client.py | 39 +++++++++++++------ 4 files changed, 55 insertions(+), 17 deletions(-) diff --git a/tests/unit/gapic/logging_v2/test_config_service_v2.py b/tests/unit/gapic/logging_v2/test_config_service_v2.py index cd5d52fdc..32dc4236b 100644 --- a/tests/unit/gapic/logging_v2/test_config_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_config_service_v2.py @@ -98,17 +98,24 @@ def test__get_default_mtls_endpoint(): ConfigServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi ) + def test_config_default_client_info_headers(): import re import pkg_resources + # test that DEFAULT_CLIENT_INFO contains the expected gapic headers # go/cloud-api-headers-2019 - gapic_header_regex = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') - detected_info = google.cloud.logging_v2.services.config_service_v2.transports.base.DEFAULT_CLIENT_INFO + gapic_header_regex = re.compile( + r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+" + ) + detected_info = ( + google.cloud.logging_v2.services.config_service_v2.transports.base.DEFAULT_CLIENT_INFO + ) assert detected_info is not None detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" "))) assert gapic_header_regex.match(detected_agent) + @pytest.mark.parametrize( "client_class,transport_name", [ diff --git a/tests/unit/gapic/logging_v2/test_logging_service_v2.py b/tests/unit/gapic/logging_v2/test_logging_service_v2.py index 43f978ba1..e68da0b58 100644 --- a/tests/unit/gapic/logging_v2/test_logging_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_logging_service_v2.py @@ -70,17 +70,24 @@ def modify_default_endpoint(client): else client.DEFAULT_ENDPOINT ) + def test_logging_default_client_info_headers(): import re import pkg_resources + # test that DEFAULT_CLIENT_INFO contains the expected gapic headers # go/cloud-api-headers-2019 - gapic_header_regex = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') - detected_info = google.cloud.logging_v2.services.logging_service_v2.transports.base.DEFAULT_CLIENT_INFO + gapic_header_regex = re.compile( + r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+" + ) + detected_info = ( + google.cloud.logging_v2.services.logging_service_v2.transports.base.DEFAULT_CLIENT_INFO + ) assert detected_info is not None detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" "))) assert gapic_header_regex.match(detected_agent) + def test__get_default_mtls_endpoint(): api_endpoint = "example.googleapis.com" api_mtls_endpoint = "example.mtls.googleapis.com" diff --git a/tests/unit/gapic/logging_v2/test_metrics_service_v2.py b/tests/unit/gapic/logging_v2/test_metrics_service_v2.py index 55b01b7d7..34cdff23a 100644 --- a/tests/unit/gapic/logging_v2/test_metrics_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_metrics_service_v2.py @@ -98,17 +98,24 @@ def test__get_default_mtls_endpoint(): == non_googleapi ) + def test_metrics_default_client_info_headers(): import re import pkg_resources + # test that DEFAULT_CLIENT_INFO contains the expected gapic headers # go/cloud-api-headers-2019 - gapic_header_regex = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') - detected_info = google.cloud.logging_v2.services.metrics_service_v2.transports.base.DEFAULT_CLIENT_INFO + gapic_header_regex = re.compile( + r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+" + ) + detected_info = ( + google.cloud.logging_v2.services.metrics_service_v2.transports.base.DEFAULT_CLIENT_INFO + ) assert detected_info is not None detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" "))) assert gapic_header_regex.match(detected_agent) + @pytest.mark.parametrize( "client_class,transport_name", [ diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 618ef9b36..2cbc31114 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -22,7 +22,10 @@ import mock -VENEER_HEADER_REGEX = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gccl\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') +VENEER_HEADER_REGEX = re.compile( + r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gccl\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+" +) + def _make_credentials(): import google.auth.credentials @@ -158,21 +161,29 @@ def test_veneer_grpc_headers(self): # ensure client info is set on client object client = self._make_one(project=self.PROJECT, credentials=creds, _use_grpc=True) self.assertIsNotNone(client._client_info) - user_agent_sorted = " ".join(sorted(client._client_info.to_user_agent().split(" "))) + user_agent_sorted = " ".join( + sorted(client._client_info.to_user_agent().split(" ")) + ) self.assertTrue(VENEER_HEADER_REGEX.match(user_agent_sorted)) # ensure client info is propagated to gapic wrapped methods patch = mock.patch("google.api_core.gapic_v1.method.wrap_method") with patch as gapic_mock: - client.logging_api # initialize logging api - client.metrics_api # initialize metrics api - client.sinks_api # initialize sinks api + client.logging_api # initialize logging api + client.metrics_api # initialize metrics api + client.sinks_api # initialize sinks api wrapped_call_list = gapic_mock.call_args_list - num_api_calls = 37 # expected number of distinct APIs in all gapic services (logging,metrics,sinks) - self.assertGreaterEqual(len(wrapped_call_list), num_api_calls, "unexpected number of APIs wrapped") + num_api_calls = 37 # expected number of distinct APIs in all gapic services (logging,metrics,sinks) + self.assertGreaterEqual( + len(wrapped_call_list), + num_api_calls, + "unexpected number of APIs wrapped", + ) for call in wrapped_call_list: client_info = call.kwargs["client_info"] self.assertIsNotNone(client_info) - wrapped_user_agent_sorted = " ".join(sorted(client_info.to_user_agent().split(" "))) + wrapped_user_agent_sorted = " ".join( + sorted(client_info.to_user_agent().split(" ")) + ) self.assertTrue(VENEER_HEADER_REGEX.match(wrapped_user_agent_sorted)) def test_veneer_http_headers(self): @@ -181,14 +192,20 @@ def test_veneer_http_headers(self): # go/cloud-api-headers-2019 creds = _make_credentials() # ensure client info is set on client object - client = self._make_one(project=self.PROJECT, credentials=creds, _use_grpc=False) + client = self._make_one( + project=self.PROJECT, credentials=creds, _use_grpc=False + ) self.assertIsNotNone(client._client_info) - user_agent_sorted = " ".join(sorted(client._client_info.to_user_agent().split(" "))) + user_agent_sorted = " ".join( + sorted(client._client_info.to_user_agent().split(" ")) + ) self.assertTrue(VENEER_HEADER_REGEX.match(user_agent_sorted)) # ensure client info is propagated to _connection object connection_user_agent = client._connection._client_info.to_user_agent() self.assertIsNotNone(connection_user_agent) - connection_user_agent_sorted = " ".join(sorted(connection_user_agent.split(" "))) + connection_user_agent_sorted = " ".join( + sorted(connection_user_agent.split(" ")) + ) self.assertTrue(VENEER_HEADER_REGEX.match(connection_user_agent_sorted)) def test_no_gapic_ctor(self): From d46c642ac845271585d892242a12c5c8ca2b2add Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 1 Dec 2022 18:45:43 -0800 Subject: [PATCH 6/9] convert client info into gapic subclass --- google/cloud/logging_v2/_gapic.py | 38 ++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/google/cloud/logging_v2/_gapic.py b/google/cloud/logging_v2/_gapic.py index 5fa31b9e7..132116895 100644 --- a/google/cloud/logging_v2/_gapic.py +++ b/google/cloud/logging_v2/_gapic.py @@ -35,6 +35,9 @@ from google.cloud.logging_v2.sink import Sink from google.cloud.logging_v2.metric import Metric +from google.api_core import client_info +from google.api_core import gapic_v1 + class _LoggingAPI(object): """Helper mapping logging-related APIs.""" @@ -561,6 +564,20 @@ def _log_entry_mapping_to_pb(mapping): ParseDict(mapping, entry_pb) return LogEntryPB(entry_pb) +def _client_info_to_gapic(input_info): + """ + Helper function to convert api_core.client_info to + api_core.gapic_v1.client_info subclass + """ + return gapic_v1.client_info.ClientInfo( + python_version=input_info.python_version, + grpc_version = input_info.grpc_version, + api_core_version = input_info.api_core_version, + gapic_version = input_info.gapic_version, + client_library_version = input_info.client_library_version, + user_agent = input_info.user_agent, + rest_version = input_info.rest_version, + ) def make_logging_api(client): """Create an instance of the Logging API adapter. @@ -572,9 +589,14 @@ def make_logging_api(client): Returns: _LoggingAPI: A metrics API instance with the proper credentials. """ + info = client._client_info + if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance(info, client_info.ClientInfo): + # convert into gapic-compatible subclass + info = _client_info_to_gapic(info) + generated = LoggingServiceV2Client( credentials=client._credentials, - client_info=client._client_info, + client_info=info, client_options=client._client_options, ) return _LoggingAPI(generated, client) @@ -590,9 +612,14 @@ def make_metrics_api(client): Returns: _MetricsAPI: A metrics API instance with the proper credentials. """ + info = client._client_info + if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance(info, client_info.ClientInfo): + # convert into gapic-compatible subclass + info = _client_info_to_gapic(info) + generated = MetricsServiceV2Client( credentials=client._credentials, - client_info=client._client_info, + client_info=info, client_options=client._client_options, ) return _MetricsAPI(generated, client) @@ -608,9 +635,14 @@ def make_sinks_api(client): Returns: _SinksAPI: A metrics API instance with the proper credentials. """ + info = client._client_info + if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance(info, client_info.ClientInfo): + # convert into gapic-compatible subclass + info = _client_info_to_gapic(info) + generated = ConfigServiceV2Client( credentials=client._credentials, - client_info=client._client_info, + client_info=info, client_options=client._client_options, ) return _SinksAPI(generated, client) From 0a33d568cb6f92a8021b7336599a935a7ef9e103 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 1 Dec 2022 18:47:09 -0800 Subject: [PATCH 7/9] fixed lint issues --- google/cloud/logging_v2/_gapic.py | 28 ++++++++----- .../logging_v2/test_config_service_v2.py | 11 +++++- .../logging_v2/test_logging_service_v2.py | 11 +++++- .../logging_v2/test_metrics_service_v2.py | 11 +++++- tests/unit/test_client.py | 39 +++++++++++++------ 5 files changed, 73 insertions(+), 27 deletions(-) diff --git a/google/cloud/logging_v2/_gapic.py b/google/cloud/logging_v2/_gapic.py index 132116895..85e270e27 100644 --- a/google/cloud/logging_v2/_gapic.py +++ b/google/cloud/logging_v2/_gapic.py @@ -564,21 +564,23 @@ def _log_entry_mapping_to_pb(mapping): ParseDict(mapping, entry_pb) return LogEntryPB(entry_pb) + def _client_info_to_gapic(input_info): """ - Helper function to convert api_core.client_info to + Helper function to convert api_core.client_info to api_core.gapic_v1.client_info subclass """ return gapic_v1.client_info.ClientInfo( python_version=input_info.python_version, - grpc_version = input_info.grpc_version, - api_core_version = input_info.api_core_version, - gapic_version = input_info.gapic_version, - client_library_version = input_info.client_library_version, - user_agent = input_info.user_agent, - rest_version = input_info.rest_version, + grpc_version=input_info.grpc_version, + api_core_version=input_info.api_core_version, + gapic_version=input_info.gapic_version, + client_library_version=input_info.client_library_version, + user_agent=input_info.user_agent, + rest_version=input_info.rest_version, ) + def make_logging_api(client): """Create an instance of the Logging API adapter. @@ -590,7 +592,9 @@ def make_logging_api(client): _LoggingAPI: A metrics API instance with the proper credentials. """ info = client._client_info - if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance(info, client_info.ClientInfo): + if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance( + info, client_info.ClientInfo + ): # convert into gapic-compatible subclass info = _client_info_to_gapic(info) @@ -613,7 +617,9 @@ def make_metrics_api(client): _MetricsAPI: A metrics API instance with the proper credentials. """ info = client._client_info - if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance(info, client_info.ClientInfo): + if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance( + info, client_info.ClientInfo + ): # convert into gapic-compatible subclass info = _client_info_to_gapic(info) @@ -636,7 +642,9 @@ def make_sinks_api(client): _SinksAPI: A metrics API instance with the proper credentials. """ info = client._client_info - if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance(info, client_info.ClientInfo): + if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance( + info, client_info.ClientInfo + ): # convert into gapic-compatible subclass info = _client_info_to_gapic(info) diff --git a/tests/unit/gapic/logging_v2/test_config_service_v2.py b/tests/unit/gapic/logging_v2/test_config_service_v2.py index cd5d52fdc..32dc4236b 100644 --- a/tests/unit/gapic/logging_v2/test_config_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_config_service_v2.py @@ -98,17 +98,24 @@ def test__get_default_mtls_endpoint(): ConfigServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi ) + def test_config_default_client_info_headers(): import re import pkg_resources + # test that DEFAULT_CLIENT_INFO contains the expected gapic headers # go/cloud-api-headers-2019 - gapic_header_regex = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') - detected_info = google.cloud.logging_v2.services.config_service_v2.transports.base.DEFAULT_CLIENT_INFO + gapic_header_regex = re.compile( + r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+" + ) + detected_info = ( + google.cloud.logging_v2.services.config_service_v2.transports.base.DEFAULT_CLIENT_INFO + ) assert detected_info is not None detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" "))) assert gapic_header_regex.match(detected_agent) + @pytest.mark.parametrize( "client_class,transport_name", [ diff --git a/tests/unit/gapic/logging_v2/test_logging_service_v2.py b/tests/unit/gapic/logging_v2/test_logging_service_v2.py index 43f978ba1..e68da0b58 100644 --- a/tests/unit/gapic/logging_v2/test_logging_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_logging_service_v2.py @@ -70,17 +70,24 @@ def modify_default_endpoint(client): else client.DEFAULT_ENDPOINT ) + def test_logging_default_client_info_headers(): import re import pkg_resources + # test that DEFAULT_CLIENT_INFO contains the expected gapic headers # go/cloud-api-headers-2019 - gapic_header_regex = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') - detected_info = google.cloud.logging_v2.services.logging_service_v2.transports.base.DEFAULT_CLIENT_INFO + gapic_header_regex = re.compile( + r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+" + ) + detected_info = ( + google.cloud.logging_v2.services.logging_service_v2.transports.base.DEFAULT_CLIENT_INFO + ) assert detected_info is not None detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" "))) assert gapic_header_regex.match(detected_agent) + def test__get_default_mtls_endpoint(): api_endpoint = "example.googleapis.com" api_mtls_endpoint = "example.mtls.googleapis.com" diff --git a/tests/unit/gapic/logging_v2/test_metrics_service_v2.py b/tests/unit/gapic/logging_v2/test_metrics_service_v2.py index 55b01b7d7..34cdff23a 100644 --- a/tests/unit/gapic/logging_v2/test_metrics_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_metrics_service_v2.py @@ -98,17 +98,24 @@ def test__get_default_mtls_endpoint(): == non_googleapi ) + def test_metrics_default_client_info_headers(): import re import pkg_resources + # test that DEFAULT_CLIENT_INFO contains the expected gapic headers # go/cloud-api-headers-2019 - gapic_header_regex = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') - detected_info = google.cloud.logging_v2.services.metrics_service_v2.transports.base.DEFAULT_CLIENT_INFO + gapic_header_regex = re.compile( + r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+" + ) + detected_info = ( + google.cloud.logging_v2.services.metrics_service_v2.transports.base.DEFAULT_CLIENT_INFO + ) assert detected_info is not None detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" "))) assert gapic_header_regex.match(detected_agent) + @pytest.mark.parametrize( "client_class,transport_name", [ diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 618ef9b36..2cbc31114 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -22,7 +22,10 @@ import mock -VENEER_HEADER_REGEX = re.compile(r'gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gccl\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+') +VENEER_HEADER_REGEX = re.compile( + r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gccl\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+" +) + def _make_credentials(): import google.auth.credentials @@ -158,21 +161,29 @@ def test_veneer_grpc_headers(self): # ensure client info is set on client object client = self._make_one(project=self.PROJECT, credentials=creds, _use_grpc=True) self.assertIsNotNone(client._client_info) - user_agent_sorted = " ".join(sorted(client._client_info.to_user_agent().split(" "))) + user_agent_sorted = " ".join( + sorted(client._client_info.to_user_agent().split(" ")) + ) self.assertTrue(VENEER_HEADER_REGEX.match(user_agent_sorted)) # ensure client info is propagated to gapic wrapped methods patch = mock.patch("google.api_core.gapic_v1.method.wrap_method") with patch as gapic_mock: - client.logging_api # initialize logging api - client.metrics_api # initialize metrics api - client.sinks_api # initialize sinks api + client.logging_api # initialize logging api + client.metrics_api # initialize metrics api + client.sinks_api # initialize sinks api wrapped_call_list = gapic_mock.call_args_list - num_api_calls = 37 # expected number of distinct APIs in all gapic services (logging,metrics,sinks) - self.assertGreaterEqual(len(wrapped_call_list), num_api_calls, "unexpected number of APIs wrapped") + num_api_calls = 37 # expected number of distinct APIs in all gapic services (logging,metrics,sinks) + self.assertGreaterEqual( + len(wrapped_call_list), + num_api_calls, + "unexpected number of APIs wrapped", + ) for call in wrapped_call_list: client_info = call.kwargs["client_info"] self.assertIsNotNone(client_info) - wrapped_user_agent_sorted = " ".join(sorted(client_info.to_user_agent().split(" "))) + wrapped_user_agent_sorted = " ".join( + sorted(client_info.to_user_agent().split(" ")) + ) self.assertTrue(VENEER_HEADER_REGEX.match(wrapped_user_agent_sorted)) def test_veneer_http_headers(self): @@ -181,14 +192,20 @@ def test_veneer_http_headers(self): # go/cloud-api-headers-2019 creds = _make_credentials() # ensure client info is set on client object - client = self._make_one(project=self.PROJECT, credentials=creds, _use_grpc=False) + client = self._make_one( + project=self.PROJECT, credentials=creds, _use_grpc=False + ) self.assertIsNotNone(client._client_info) - user_agent_sorted = " ".join(sorted(client._client_info.to_user_agent().split(" "))) + user_agent_sorted = " ".join( + sorted(client._client_info.to_user_agent().split(" ")) + ) self.assertTrue(VENEER_HEADER_REGEX.match(user_agent_sorted)) # ensure client info is propagated to _connection object connection_user_agent = client._connection._client_info.to_user_agent() self.assertIsNotNone(connection_user_agent) - connection_user_agent_sorted = " ".join(sorted(connection_user_agent.split(" "))) + connection_user_agent_sorted = " ".join( + sorted(connection_user_agent.split(" ")) + ) self.assertTrue(VENEER_HEADER_REGEX.match(connection_user_agent_sorted)) def test_no_gapic_ctor(self): From f52dd6c32ba777affa1acf1812a9b200512708e7 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 1 Dec 2022 19:07:48 -0800 Subject: [PATCH 8/9] improved type checking --- google/cloud/logging_v2/_gapic.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/google/cloud/logging_v2/_gapic.py b/google/cloud/logging_v2/_gapic.py index 85e270e27..b71d3d92c 100644 --- a/google/cloud/logging_v2/_gapic.py +++ b/google/cloud/logging_v2/_gapic.py @@ -592,9 +592,7 @@ def make_logging_api(client): _LoggingAPI: A metrics API instance with the proper credentials. """ info = client._client_info - if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance( - info, client_info.ClientInfo - ): + if type(info) == client_info.ClientInfo: # convert into gapic-compatible subclass info = _client_info_to_gapic(info) @@ -617,9 +615,7 @@ def make_metrics_api(client): _MetricsAPI: A metrics API instance with the proper credentials. """ info = client._client_info - if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance( - info, client_info.ClientInfo - ): + if type(info) == client_info.ClientInfo: # convert into gapic-compatible subclass info = _client_info_to_gapic(info) @@ -642,9 +638,7 @@ def make_sinks_api(client): _SinksAPI: A metrics API instance with the proper credentials. """ info = client._client_info - if (not isinstance(info, gapic_v1.client_info.ClientInfo)) and isinstance( - info, client_info.ClientInfo - ): + if type(info) == client_info.ClientInfo: # convert into gapic-compatible subclass info = _client_info_to_gapic(info) From bfddc75f83228fe3e1031ca888e4c5f2c072b48f Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 5 Dec 2022 14:33:55 -0800 Subject: [PATCH 9/9] removed links --- tests/unit/gapic/logging_v2/test_config_service_v2.py | 1 - tests/unit/gapic/logging_v2/test_logging_service_v2.py | 1 - tests/unit/gapic/logging_v2/test_metrics_service_v2.py | 1 - tests/unit/test_client.py | 2 -- 4 files changed, 5 deletions(-) diff --git a/tests/unit/gapic/logging_v2/test_config_service_v2.py b/tests/unit/gapic/logging_v2/test_config_service_v2.py index 32dc4236b..8e8671e68 100644 --- a/tests/unit/gapic/logging_v2/test_config_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_config_service_v2.py @@ -104,7 +104,6 @@ def test_config_default_client_info_headers(): import pkg_resources # test that DEFAULT_CLIENT_INFO contains the expected gapic headers - # go/cloud-api-headers-2019 gapic_header_regex = re.compile( r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+" ) diff --git a/tests/unit/gapic/logging_v2/test_logging_service_v2.py b/tests/unit/gapic/logging_v2/test_logging_service_v2.py index e68da0b58..832ad63dc 100644 --- a/tests/unit/gapic/logging_v2/test_logging_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_logging_service_v2.py @@ -76,7 +76,6 @@ def test_logging_default_client_info_headers(): import pkg_resources # test that DEFAULT_CLIENT_INFO contains the expected gapic headers - # go/cloud-api-headers-2019 gapic_header_regex = re.compile( r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+" ) diff --git a/tests/unit/gapic/logging_v2/test_metrics_service_v2.py b/tests/unit/gapic/logging_v2/test_metrics_service_v2.py index 34cdff23a..4f9e2347c 100644 --- a/tests/unit/gapic/logging_v2/test_metrics_service_v2.py +++ b/tests/unit/gapic/logging_v2/test_metrics_service_v2.py @@ -104,7 +104,6 @@ def test_metrics_default_client_info_headers(): import pkg_resources # test that DEFAULT_CLIENT_INFO contains the expected gapic headers - # go/cloud-api-headers-2019 gapic_header_regex = re.compile( r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+" ) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 2cbc31114..1c47a343b 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -156,7 +156,6 @@ def make_api(client_obj): def test_veneer_grpc_headers(self): # test that client APIs have client_info populated with the expected veneer headers # required for proper instrumentation - # go/cloud-api-headers-2019 creds = _make_credentials() # ensure client info is set on client object client = self._make_one(project=self.PROJECT, credentials=creds, _use_grpc=True) @@ -189,7 +188,6 @@ def test_veneer_grpc_headers(self): def test_veneer_http_headers(self): # test that http APIs have client_info populated with the expected veneer headers # required for proper instrumentation - # go/cloud-api-headers-2019 creds = _make_credentials() # ensure client info is set on client object client = self._make_one(