From e66243cfeace4fb774c879c11db05870cf8f13d4 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Thu, 25 Jun 2020 01:15:36 +0000 Subject: [PATCH 1/5] feat: allow quota project to be passed to create_channel --- google/api_core/grpc_helpers.py | 24 +++++++++++++++++++++--- google/api_core/grpc_helpers_async.py | 13 +++++++++++-- noxfile.py | 3 +++ tests/asyncio/test_grpc_helpers_async.py | 17 +++++++++++++++++ tests/unit/test_grpc_helpers.py | 23 +++++++++++++++++++++++ 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/google/api_core/grpc_helpers.py b/google/api_core/grpc_helpers.py index 2203968e..dfc8442d 100644 --- a/google/api_core/grpc_helpers.py +++ b/google/api_core/grpc_helpers.py @@ -176,7 +176,12 @@ def wrap_errors(callable_): return _wrap_unary_errors(callable_) -def _create_composite_credentials(credentials=None, credentials_file=None, scopes=None, ssl_credentials=None): +def _create_composite_credentials( + credentials=None, + credentials_file=None, + scopes=None, + ssl_credentials=None, + quota_project_id=None): """Create the composite credentials for secure channels. Args: @@ -191,6 +196,7 @@ def _create_composite_credentials(credentials=None, credentials_file=None, scope are passed to :func:`google.auth.default`. ssl_credentials (grpc.ChannelCredentials): Optional SSL channel credentials. This can be used to specify different certificates. + quota_project_id (str): An optional project to use for billing and quota. Returns: grpc.ChannelCredentials: The composed channel credentials object. @@ -210,6 +216,9 @@ def _create_composite_credentials(credentials=None, credentials_file=None, scope else: credentials, _ = google.auth.default(scopes=scopes) + if quota_project_id: + credentials = credentials.with_quota_project(quota_project_id) + request = google.auth.transport.requests.Request() # Create the metadata plugin for inserting the authorization header. @@ -229,7 +238,14 @@ def _create_composite_credentials(credentials=None, credentials_file=None, scope ) -def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, credentials_file=None, **kwargs): +def create_channel( + target, + credentials=None, + scopes=None, + ssl_credentials=None, + credentials_file=None, + quota_project_id=None, + **kwargs): """Create a secure channel with credentials. Args: @@ -245,6 +261,7 @@ def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, credentials_file (str): A file with credentials that can be loaded with :func:`google.auth.load_credentials_from_file`. This argument is mutually exclusive with credentials. + quota_project_id (str): An optional project to use for billing and quota. kwargs: Additional key-word args passed to :func:`grpc_gcp.secure_channel` or :func:`grpc.secure_channel`. @@ -259,7 +276,8 @@ def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, credentials=credentials, credentials_file=credentials_file, scopes=scopes, - ssl_credentials=ssl_credentials + ssl_credentials=ssl_credentials, + quota_project_id=quota_project_id, ) if HAS_GRPC_GCP: diff --git a/google/api_core/grpc_helpers_async.py b/google/api_core/grpc_helpers_async.py index 1dfe8b9a..9a994e9f 100644 --- a/google/api_core/grpc_helpers_async.py +++ b/google/api_core/grpc_helpers_async.py @@ -206,7 +206,14 @@ def wrap_errors(callable_): return _wrap_stream_errors(callable_) -def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, credentials_file=None, **kwargs): +def create_channel( + target, + credentials=None, + scopes=None, + ssl_credentials=None, + credentials_file=None, + quota_project_id=None, + **kwargs): """Create an AsyncIO secure channel with credentials. Args: @@ -222,6 +229,7 @@ def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, credentials_file (str): A file with credentials that can be loaded with :func:`google.auth.load_credentials_from_file`. This argument is mutually exclusive with credentials. + quota_project_id (str): An optional project to use for billing and quota. kwargs: Additional key-word args passed to :func:`aio.secure_channel`. Returns: @@ -235,7 +243,8 @@ def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, credentials=credentials, credentials_file=credentials_file, scopes=scopes, - ssl_credentials=ssl_credentials + ssl_credentials=ssl_credentials, + quota_project_id=quota_project_id, ) return aio.secure_channel(target, composite_credentials, **kwargs) diff --git a/noxfile.py b/noxfile.py index 989bb9be..2ea401b9 100644 --- a/noxfile.py +++ b/noxfile.py @@ -45,6 +45,9 @@ def default(session): session.install("mock", "pytest", "pytest-cov", "grpcio >= 1.0.2") session.install("-e", ".") + # TODO(busunkim): Remove once quota project change is merged + session.install("--force-reinstall", "git+https://github.com/googleapis/google-auth-library-python.git@more-quota-project") + pytest_args = [ "python", "-m", diff --git a/tests/asyncio/test_grpc_helpers_async.py b/tests/asyncio/test_grpc_helpers_async.py index d56c4c60..0868f42b 100644 --- a/tests/asyncio/test_grpc_helpers_async.py +++ b/tests/asyncio/test_grpc_helpers_async.py @@ -363,6 +363,23 @@ def test_create_channel_explicit_scoped(grpc_secure_channel, composite_creds_cal grpc_secure_channel.assert_called_once_with(target, composite_creds) +@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.experimental.aio.secure_channel") +def test_create_channel_explicit_with_scopes(grpc_secure_channel, composite_creds_call): + target = "example.com:443" + composite_creds = composite_creds_call.return_value + + credentials = mock.create_autospec(google.auth.credentials.Credentials, instance=True) + + channel = grpc_helpers_async.create_channel( + target, credentials=credentials, quota_project_id="project-foo" + ) + + credentials.with_quota_project.assert_called_once_with("project-foo") + assert channel is grpc_secure_channel.return_value + grpc_secure_channel.assert_called_once_with(target, composite_creds) + + @mock.patch("grpc.composite_channel_credentials") @mock.patch("grpc.experimental.aio.secure_channel") @mock.patch( diff --git a/tests/unit/test_grpc_helpers.py b/tests/unit/test_grpc_helpers.py index e2f36662..f8fed403 100644 --- a/tests/unit/test_grpc_helpers.py +++ b/tests/unit/test_grpc_helpers.py @@ -335,6 +335,29 @@ def test_create_channel_explicit_scoped(grpc_secure_channel, composite_creds_cal grpc_secure_channel.assert_called_once_with(target, composite_creds) +@mock.patch("grpc.composite_channel_credentials") +@mock.patch("grpc.secure_channel") +def test_create_channel_explicit_with_quota_project(grpc_secure_channel, composite_creds_call): + target = "example.com:443" + composite_creds = composite_creds_call.return_value + + credentials = mock.create_autospec(google.auth.credentials.Credentials, instance=True) + + channel = grpc_helpers.create_channel( + target, + credentials=credentials, + quota_project_id="project-foo" + ) + + credentials.with_quota_project.assert_called_once_with("project-foo") + + assert channel is grpc_secure_channel.return_value + if grpc_helpers.HAS_GRPC_GCP: + grpc_secure_channel.assert_called_once_with(target, composite_creds, None) + else: + grpc_secure_channel.assert_called_once_with(target, composite_creds) + + @mock.patch("grpc.composite_channel_credentials") @mock.patch("grpc.secure_channel") @mock.patch( From 19c7a5de460d6d88df91c7331adcb3fb5e9573e4 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Thu, 25 Jun 2020 01:18:41 +0000 Subject: [PATCH 2/5] chore: update test name --- tests/asyncio/test_grpc_helpers_async.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/asyncio/test_grpc_helpers_async.py b/tests/asyncio/test_grpc_helpers_async.py index 0868f42b..924a74ca 100644 --- a/tests/asyncio/test_grpc_helpers_async.py +++ b/tests/asyncio/test_grpc_helpers_async.py @@ -365,7 +365,7 @@ def test_create_channel_explicit_scoped(grpc_secure_channel, composite_creds_cal @mock.patch("grpc.composite_channel_credentials") @mock.patch("grpc.experimental.aio.secure_channel") -def test_create_channel_explicit_with_scopes(grpc_secure_channel, composite_creds_call): +def test_create_channel_explicit_with_quota_project(grpc_secure_channel, composite_creds_call): target = "example.com:443" composite_creds = composite_creds_call.return_value From a5aa5ea5504cbb5598e4ede2b96879692af72bf6 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Tue, 14 Jul 2020 05:05:54 +0000 Subject: [PATCH 3/5] chore: lint and increase auth lib version --- google/api_core/grpc_helpers.py | 3 ++- google/api_core/grpc_helpers_async.py | 3 ++- noxfile.py | 3 --- setup.py | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/google/api_core/grpc_helpers.py b/google/api_core/grpc_helpers.py index dfc8442d..5abefd56 100644 --- a/google/api_core/grpc_helpers.py +++ b/google/api_core/grpc_helpers.py @@ -181,7 +181,8 @@ def _create_composite_credentials( credentials_file=None, scopes=None, ssl_credentials=None, - quota_project_id=None): + quota_project_id=None + ): """Create the composite credentials for secure channels. Args: diff --git a/google/api_core/grpc_helpers_async.py b/google/api_core/grpc_helpers_async.py index 9a994e9f..62301f9d 100644 --- a/google/api_core/grpc_helpers_async.py +++ b/google/api_core/grpc_helpers_async.py @@ -213,7 +213,8 @@ def create_channel( ssl_credentials=None, credentials_file=None, quota_project_id=None, - **kwargs): + **kwargs + ): """Create an AsyncIO secure channel with credentials. Args: diff --git a/noxfile.py b/noxfile.py index 2ea401b9..989bb9be 100644 --- a/noxfile.py +++ b/noxfile.py @@ -45,9 +45,6 @@ def default(session): session.install("mock", "pytest", "pytest-cov", "grpcio >= 1.0.2") session.install("-e", ".") - # TODO(busunkim): Remove once quota project change is merged - session.install("--force-reinstall", "git+https://github.com/googleapis/google-auth-library-python.git@more-quota-project") - pytest_args = [ "python", "-m", diff --git a/setup.py b/setup.py index efa4a12a..8cd84400 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ dependencies = [ "googleapis-common-protos >= 1.6.0, < 2.0dev", "protobuf >= 3.12.0", - "google-auth >= 1.18.0, < 2.0dev", + "google-auth >= 1.19.0, < 2.0dev", "requests >= 2.18.0, < 3.0.0dev", "setuptools >= 34.0.0", "six >= 1.10.0", From 090f78b32e3cb97846e0213ff7095c8e5f9f57f3 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Tue, 14 Jul 2020 05:22:25 +0000 Subject: [PATCH 4/5] chore: fix lint --- google/api_core/grpc_helpers.py | 3 +-- google/api_core/grpc_helpers_async.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/google/api_core/grpc_helpers.py b/google/api_core/grpc_helpers.py index 5abefd56..dfc8442d 100644 --- a/google/api_core/grpc_helpers.py +++ b/google/api_core/grpc_helpers.py @@ -181,8 +181,7 @@ def _create_composite_credentials( credentials_file=None, scopes=None, ssl_credentials=None, - quota_project_id=None - ): + quota_project_id=None): """Create the composite credentials for secure channels. Args: diff --git a/google/api_core/grpc_helpers_async.py b/google/api_core/grpc_helpers_async.py index 62301f9d..9a994e9f 100644 --- a/google/api_core/grpc_helpers_async.py +++ b/google/api_core/grpc_helpers_async.py @@ -213,8 +213,7 @@ def create_channel( ssl_credentials=None, credentials_file=None, quota_project_id=None, - **kwargs - ): + **kwargs): """Create an AsyncIO secure channel with credentials. Args: From c84963a2e850c2aa6f78496078ade587a2daadd2 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Thu, 16 Jul 2020 14:04:48 -0700 Subject: [PATCH 5/5] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8cd84400..6e82e54e 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ dependencies = [ "googleapis-common-protos >= 1.6.0, < 2.0dev", "protobuf >= 3.12.0", - "google-auth >= 1.19.0, < 2.0dev", + "google-auth >= 1.19.1, < 2.0dev", "requests >= 2.18.0, < 3.0.0dev", "setuptools >= 34.0.0", "six >= 1.10.0",