From 6e31dbc9416d41c9f19e4341d4b492ba7bf7211e Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 9 Nov 2021 15:38:35 -0500 Subject: [PATCH 01/15] chore: use gapic-generator-python 0.56.2 (#161) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: update Java and Python dependencies PiperOrigin-RevId: 408420890 Source-Link: https://github.com/googleapis/googleapis/commit/2921f9fb3bfbd16f6b2da0104373e2b47a80a65e Source-Link: https://github.com/googleapis/googleapis-gen/commit/6598ca8cbbf5226733a099c4506518a5af6ff74c Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiNjU5OGNhOGNiYmY1MjI2NzMzYTA5OWM0NTA2NTE4YTVhZjZmZjc0YyJ9 * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot --- .../services/cloud_scheduler/async_client.py | 13 +-- .../services/cloud_scheduler/client.py | 25 ++++-- .../cloud_scheduler/transports/base.py | 8 +- .../cloud_scheduler/transports/grpc.py | 4 +- .../transports/grpc_asyncio.py | 4 +- google/cloud/scheduler_v1/types/job.py | 3 + google/cloud/scheduler_v1/types/target.py | 2 + .../services/cloud_scheduler/async_client.py | 13 +-- .../services/cloud_scheduler/client.py | 25 ++++-- .../cloud_scheduler/transports/base.py | 8 +- .../cloud_scheduler/transports/grpc.py | 4 +- .../transports/grpc_asyncio.py | 4 +- google/cloud/scheduler_v1beta1/types/job.py | 3 + .../cloud/scheduler_v1beta1/types/target.py | 2 + .../scheduler_v1/test_cloud_scheduler.py | 80 ++++++++++++++----- .../scheduler_v1beta1/test_cloud_scheduler.py | 80 ++++++++++++++----- 16 files changed, 196 insertions(+), 82 deletions(-) diff --git a/google/cloud/scheduler_v1/services/cloud_scheduler/async_client.py b/google/cloud/scheduler_v1/services/cloud_scheduler/async_client.py index 743e3616..e7e997e2 100644 --- a/google/cloud/scheduler_v1/services/cloud_scheduler/async_client.py +++ b/google/cloud/scheduler_v1/services/cloud_scheduler/async_client.py @@ -19,14 +19,17 @@ from typing import Dict, Sequence, Tuple, Type, Union import pkg_resources -from google.api_core.client_options import ClientOptions # type: ignore -from google.api_core import exceptions as core_exceptions # type: ignore -from google.api_core import gapic_v1 # type: ignore -from google.api_core import retry as retries # type: ignore +from google.api_core.client_options import ClientOptions +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.oauth2 import service_account # type: ignore -OptionalRetry = Union[retries.Retry, object] +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore from google.cloud.scheduler_v1.services.cloud_scheduler import pagers from google.cloud.scheduler_v1.types import cloudscheduler diff --git a/google/cloud/scheduler_v1/services/cloud_scheduler/client.py b/google/cloud/scheduler_v1/services/cloud_scheduler/client.py index 588cd9c6..938b6905 100644 --- a/google/cloud/scheduler_v1/services/cloud_scheduler/client.py +++ b/google/cloud/scheduler_v1/services/cloud_scheduler/client.py @@ -14,23 +14,25 @@ # limitations under the License. # from collections import OrderedDict -from distutils import util import os import re from typing import Dict, Optional, Sequence, Tuple, Type, Union import pkg_resources -from google.api_core import client_options as client_options_lib # type: ignore -from google.api_core import exceptions as core_exceptions # type: ignore -from google.api_core import gapic_v1 # type: ignore -from google.api_core import retry as retries # type: ignore +from google.api_core import client_options as client_options_lib +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.oauth2 import service_account # type: ignore -OptionalRetry = Union[retries.Retry, object] +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore from google.cloud.scheduler_v1.services.cloud_scheduler import pagers from google.cloud.scheduler_v1.types import cloudscheduler @@ -303,8 +305,15 @@ def __init__( client_options = client_options_lib.ClientOptions() # Create SSL credentials for mutual TLS if needed. - use_client_cert = bool( - util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) + if os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") not in ( + "true", + "false", + ): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + use_client_cert = ( + os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true" ) client_cert_source_func = None diff --git a/google/cloud/scheduler_v1/services/cloud_scheduler/transports/base.py b/google/cloud/scheduler_v1/services/cloud_scheduler/transports/base.py index 9a116cef..ac7d4af9 100644 --- a/google/cloud/scheduler_v1/services/cloud_scheduler/transports/base.py +++ b/google/cloud/scheduler_v1/services/cloud_scheduler/transports/base.py @@ -18,10 +18,10 @@ import pkg_resources import google.auth # type: ignore -import google.api_core # type: ignore -from google.api_core import exceptions as core_exceptions # type: ignore -from google.api_core import gapic_v1 # type: ignore -from google.api_core import retry as retries # type: ignore +import google.api_core +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.oauth2 import service_account # type: ignore diff --git a/google/cloud/scheduler_v1/services/cloud_scheduler/transports/grpc.py b/google/cloud/scheduler_v1/services/cloud_scheduler/transports/grpc.py index 4d90b1bc..a1e3b7a7 100644 --- a/google/cloud/scheduler_v1/services/cloud_scheduler/transports/grpc.py +++ b/google/cloud/scheduler_v1/services/cloud_scheduler/transports/grpc.py @@ -16,8 +16,8 @@ import warnings from typing import Callable, Dict, Optional, Sequence, Tuple, Union -from google.api_core import grpc_helpers # type: ignore -from google.api_core import gapic_v1 # type: ignore +from google.api_core import grpc_helpers +from google.api_core import gapic_v1 import google.auth # type: ignore from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore diff --git a/google/cloud/scheduler_v1/services/cloud_scheduler/transports/grpc_asyncio.py b/google/cloud/scheduler_v1/services/cloud_scheduler/transports/grpc_asyncio.py index bff4a8af..af0972c9 100644 --- a/google/cloud/scheduler_v1/services/cloud_scheduler/transports/grpc_asyncio.py +++ b/google/cloud/scheduler_v1/services/cloud_scheduler/transports/grpc_asyncio.py @@ -16,8 +16,8 @@ import warnings from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union -from google.api_core import gapic_v1 # type: ignore -from google.api_core import grpc_helpers_async # type: ignore +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers_async from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore diff --git a/google/cloud/scheduler_v1/types/job.py b/google/cloud/scheduler_v1/types/job.py index 8e919e5f..883891b7 100644 --- a/google/cloud/scheduler_v1/types/job.py +++ b/google/cloud/scheduler_v1/types/job.py @@ -69,12 +69,15 @@ class Job(proto.Message): not contain more than 500 characters. pubsub_target (google.cloud.scheduler_v1.types.PubsubTarget): Pub/Sub target. + This field is a member of `oneof`_ ``target``. app_engine_http_target (google.cloud.scheduler_v1.types.AppEngineHttpTarget): App Engine HTTP target. + This field is a member of `oneof`_ ``target``. http_target (google.cloud.scheduler_v1.types.HttpTarget): HTTP target. + This field is a member of `oneof`_ ``target``. schedule (str): Required, except when used with diff --git a/google/cloud/scheduler_v1/types/target.py b/google/cloud/scheduler_v1/types/target.py index e2670972..fb5227b2 100644 --- a/google/cloud/scheduler_v1/types/target.py +++ b/google/cloud/scheduler_v1/types/target.py @@ -105,6 +105,7 @@ class HttpTarget(proto.Message): This type of authorization should generally only be used when calling Google APIs hosted on \*.googleapis.com. + This field is a member of `oneof`_ ``authorization_header``. oidc_token (google.cloud.scheduler_v1.types.OidcToken): If specified, an @@ -115,6 +116,7 @@ class HttpTarget(proto.Message): This type of authorization can be used for many scenarios, including calling Cloud Run, or endpoints where you intend to validate the token yourself. + This field is a member of `oneof`_ ``authorization_header``. """ diff --git a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/async_client.py b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/async_client.py index 0b6f09d6..913d832a 100644 --- a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/async_client.py +++ b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/async_client.py @@ -19,14 +19,17 @@ from typing import Dict, Sequence, Tuple, Type, Union import pkg_resources -from google.api_core.client_options import ClientOptions # type: ignore -from google.api_core import exceptions as core_exceptions # type: ignore -from google.api_core import gapic_v1 # type: ignore -from google.api_core import retry as retries # type: ignore +from google.api_core.client_options import ClientOptions +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.oauth2 import service_account # type: ignore -OptionalRetry = Union[retries.Retry, object] +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore from google.cloud.scheduler_v1beta1.services.cloud_scheduler import pagers from google.cloud.scheduler_v1beta1.types import cloudscheduler diff --git a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py index f1a9b24a..e0a9c803 100644 --- a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py +++ b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py @@ -14,23 +14,25 @@ # limitations under the License. # from collections import OrderedDict -from distutils import util import os import re from typing import Dict, Optional, Sequence, Tuple, Type, Union import pkg_resources -from google.api_core import client_options as client_options_lib # type: ignore -from google.api_core import exceptions as core_exceptions # type: ignore -from google.api_core import gapic_v1 # type: ignore -from google.api_core import retry as retries # type: ignore +from google.api_core import client_options as client_options_lib +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport import mtls # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.oauth2 import service_account # type: ignore -OptionalRetry = Union[retries.Retry, object] +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore from google.cloud.scheduler_v1beta1.services.cloud_scheduler import pagers from google.cloud.scheduler_v1beta1.types import cloudscheduler @@ -303,8 +305,15 @@ def __init__( client_options = client_options_lib.ClientOptions() # Create SSL credentials for mutual TLS if needed. - use_client_cert = bool( - util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) + if os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") not in ( + "true", + "false", + ): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + use_client_cert = ( + os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true" ) client_cert_source_func = None diff --git a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/base.py b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/base.py index e2586f34..02aa59c0 100644 --- a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/base.py +++ b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/base.py @@ -18,10 +18,10 @@ import pkg_resources import google.auth # type: ignore -import google.api_core # type: ignore -from google.api_core import exceptions as core_exceptions # type: ignore -from google.api_core import gapic_v1 # type: ignore -from google.api_core import retry as retries # type: ignore +import google.api_core +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries from google.auth import credentials as ga_credentials # type: ignore from google.oauth2 import service_account # type: ignore diff --git a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/grpc.py b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/grpc.py index b54fcefb..cb0787f3 100644 --- a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/grpc.py +++ b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/grpc.py @@ -16,8 +16,8 @@ import warnings from typing import Callable, Dict, Optional, Sequence, Tuple, Union -from google.api_core import grpc_helpers # type: ignore -from google.api_core import gapic_v1 # type: ignore +from google.api_core import grpc_helpers +from google.api_core import gapic_v1 import google.auth # type: ignore from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore diff --git a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/grpc_asyncio.py b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/grpc_asyncio.py index acda63e7..4936905a 100644 --- a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/grpc_asyncio.py +++ b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/grpc_asyncio.py @@ -16,8 +16,8 @@ import warnings from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union -from google.api_core import gapic_v1 # type: ignore -from google.api_core import grpc_helpers_async # type: ignore +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers_async from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore diff --git a/google/cloud/scheduler_v1beta1/types/job.py b/google/cloud/scheduler_v1beta1/types/job.py index e99d33fe..2deac0ee 100644 --- a/google/cloud/scheduler_v1beta1/types/job.py +++ b/google/cloud/scheduler_v1beta1/types/job.py @@ -69,12 +69,15 @@ class Job(proto.Message): not contain more than 500 characters. pubsub_target (google.cloud.scheduler_v1beta1.types.PubsubTarget): Pub/Sub target. + This field is a member of `oneof`_ ``target``. app_engine_http_target (google.cloud.scheduler_v1beta1.types.AppEngineHttpTarget): App Engine HTTP target. + This field is a member of `oneof`_ ``target``. http_target (google.cloud.scheduler_v1beta1.types.HttpTarget): HTTP target. + This field is a member of `oneof`_ ``target``. schedule (str): Required, except when used with diff --git a/google/cloud/scheduler_v1beta1/types/target.py b/google/cloud/scheduler_v1beta1/types/target.py index 51bf95d7..2a2761c5 100644 --- a/google/cloud/scheduler_v1beta1/types/target.py +++ b/google/cloud/scheduler_v1beta1/types/target.py @@ -106,6 +106,7 @@ class HttpTarget(proto.Message): This type of authorization should generally only be used when calling Google APIs hosted on \*.googleapis.com. + This field is a member of `oneof`_ ``authorization_header``. oidc_token (google.cloud.scheduler_v1beta1.types.OidcToken): If specified, an @@ -116,6 +117,7 @@ class HttpTarget(proto.Message): This type of authorization can be used for many scenarios, including calling Cloud Run, or endpoints where you intend to validate the token yourself. + This field is a member of `oneof`_ ``authorization_header``. """ diff --git a/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py b/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py index 1d23d860..7cd4acb5 100644 --- a/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py +++ b/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py @@ -636,7 +636,9 @@ def test_list_jobs_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].parent == "parent_value" + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val def test_list_jobs_flattened_error(): @@ -672,7 +674,9 @@ async def test_list_jobs_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].parent == "parent_value" + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val @pytest.mark.asyncio @@ -957,7 +961,9 @@ def test_get_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val def test_get_job_flattened_error(): @@ -991,7 +997,9 @@ async def test_get_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val @pytest.mark.asyncio @@ -1178,8 +1186,12 @@ def test_create_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].parent == "parent_value" - assert args[0].job == gcs_job.Job(name="name_value") + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + arg = args[0].job + mock_val = gcs_job.Job(name="name_value") + assert arg == mock_val def test_create_job_flattened_error(): @@ -1217,8 +1229,12 @@ async def test_create_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].parent == "parent_value" - assert args[0].job == gcs_job.Job(name="name_value") + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + arg = args[0].job + mock_val = gcs_job.Job(name="name_value") + assert arg == mock_val @pytest.mark.asyncio @@ -1408,8 +1424,12 @@ def test_update_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].job == gcs_job.Job(name="name_value") - assert args[0].update_mask == field_mask_pb2.FieldMask(paths=["paths_value"]) + arg = args[0].job + mock_val = gcs_job.Job(name="name_value") + assert arg == mock_val + arg = args[0].update_mask + mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) + assert arg == mock_val def test_update_job_flattened_error(): @@ -1448,8 +1468,12 @@ async def test_update_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].job == gcs_job.Job(name="name_value") - assert args[0].update_mask == field_mask_pb2.FieldMask(paths=["paths_value"]) + arg = args[0].job + mock_val = gcs_job.Job(name="name_value") + assert arg == mock_val + arg = args[0].update_mask + mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) + assert arg == mock_val @pytest.mark.asyncio @@ -1611,7 +1635,9 @@ def test_delete_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val def test_delete_job_flattened_error(): @@ -1645,7 +1671,9 @@ async def test_delete_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val @pytest.mark.asyncio @@ -1830,7 +1858,9 @@ def test_pause_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val def test_pause_job_flattened_error(): @@ -1864,7 +1894,9 @@ async def test_pause_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val @pytest.mark.asyncio @@ -2049,7 +2081,9 @@ def test_resume_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val def test_resume_job_flattened_error(): @@ -2083,7 +2117,9 @@ async def test_resume_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val @pytest.mark.asyncio @@ -2266,7 +2302,9 @@ def test_run_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val def test_run_job_flattened_error(): @@ -2300,7 +2338,9 @@ async def test_run_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val @pytest.mark.asyncio diff --git a/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py b/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py index 396e4837..091ca064 100644 --- a/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py +++ b/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py @@ -638,7 +638,9 @@ def test_list_jobs_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].parent == "parent_value" + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val def test_list_jobs_flattened_error(): @@ -674,7 +676,9 @@ async def test_list_jobs_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].parent == "parent_value" + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val @pytest.mark.asyncio @@ -959,7 +963,9 @@ def test_get_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val def test_get_job_flattened_error(): @@ -993,7 +999,9 @@ async def test_get_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val @pytest.mark.asyncio @@ -1180,8 +1188,12 @@ def test_create_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].parent == "parent_value" - assert args[0].job == gcs_job.Job(name="name_value") + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + arg = args[0].job + mock_val = gcs_job.Job(name="name_value") + assert arg == mock_val def test_create_job_flattened_error(): @@ -1219,8 +1231,12 @@ async def test_create_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].parent == "parent_value" - assert args[0].job == gcs_job.Job(name="name_value") + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + arg = args[0].job + mock_val = gcs_job.Job(name="name_value") + assert arg == mock_val @pytest.mark.asyncio @@ -1410,8 +1426,12 @@ def test_update_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].job == gcs_job.Job(name="name_value") - assert args[0].update_mask == field_mask_pb2.FieldMask(paths=["paths_value"]) + arg = args[0].job + mock_val = gcs_job.Job(name="name_value") + assert arg == mock_val + arg = args[0].update_mask + mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) + assert arg == mock_val def test_update_job_flattened_error(): @@ -1450,8 +1470,12 @@ async def test_update_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].job == gcs_job.Job(name="name_value") - assert args[0].update_mask == field_mask_pb2.FieldMask(paths=["paths_value"]) + arg = args[0].job + mock_val = gcs_job.Job(name="name_value") + assert arg == mock_val + arg = args[0].update_mask + mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) + assert arg == mock_val @pytest.mark.asyncio @@ -1613,7 +1637,9 @@ def test_delete_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val def test_delete_job_flattened_error(): @@ -1647,7 +1673,9 @@ async def test_delete_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val @pytest.mark.asyncio @@ -1832,7 +1860,9 @@ def test_pause_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val def test_pause_job_flattened_error(): @@ -1866,7 +1896,9 @@ async def test_pause_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val @pytest.mark.asyncio @@ -2051,7 +2083,9 @@ def test_resume_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val def test_resume_job_flattened_error(): @@ -2085,7 +2119,9 @@ async def test_resume_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val @pytest.mark.asyncio @@ -2268,7 +2304,9 @@ def test_run_job_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val def test_run_job_flattened_error(): @@ -2302,7 +2340,9 @@ async def test_run_job_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].name == "name_value" + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val @pytest.mark.asyncio From 60f2cfaed10f1efa11efad839e355e68156054fd Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Wed, 10 Nov 2021 20:39:00 -0500 Subject: [PATCH 02/15] chore(python): run blacken session for all directories with a noxfile (#162) Source-Link: https://github.com/googleapis/synthtool/commit/bc0de6ee2489da6fb8eafd021a8c58b5cc30c947 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:39ad8c0570e4f5d2d3124a509de4fe975e799e2b97e0f58aed88f8880d5a8b60 Co-authored-by: Owl Bot --- .github/.OwlBot.lock.yaml | 2 +- samples/snippets/create_job.py | 25 +++++++++---------------- samples/snippets/create_job_test.py | 13 +++++++------ samples/snippets/main.py | 18 ++++++++++-------- samples/snippets/main_test.py | 11 ++++++----- 5 files changed, 33 insertions(+), 36 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 108063d4..63bf76ea 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:4ee57a76a176ede9087c14330c625a71553cf9c72828b2c0ca12f5338171ba60 + digest: sha256:39ad8c0570e4f5d2d3124a509de4fe975e799e2b97e0f58aed88f8880d5a8b60 diff --git a/samples/snippets/create_job.py b/samples/snippets/create_job.py index 646a8978..aeea5750 100644 --- a/samples/snippets/create_job.py +++ b/samples/snippets/create_job.py @@ -31,27 +31,20 @@ def create_scheduler_job(project_id, location_id, service_id): # Construct the request body. job = { - 'app_engine_http_target': { - 'app_engine_routing': { - 'service': service_id - }, - 'relative_uri': '/log_payload', - 'http_method': 1, - 'body': 'Hello World'.encode() + "app_engine_http_target": { + "app_engine_routing": {"service": service_id}, + "relative_uri": "/log_payload", + "http_method": 1, + "body": "Hello World".encode(), }, - 'schedule': '* * * * *', - 'time_zone': 'America/Los_Angeles' + "schedule": "* * * * *", + "time_zone": "America/Los_Angeles", } # Use the client to send the job creation request. - response = client.create_job( - request={ - "parent": parent, - "job": job - } - ) + response = client.create_job(request={"parent": parent, "job": job}) - print('Created job: {}'.format(response.name)) + print("Created job: {}".format(response.name)) # [END cloud_scheduler_create_job] return response diff --git a/samples/snippets/create_job_test.py b/samples/snippets/create_job_test.py index e6b8a0eb..da61f0ef 100644 --- a/samples/snippets/create_job_test.py +++ b/samples/snippets/create_job_test.py @@ -16,18 +16,19 @@ import create_job -TEST_PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT') -TEST_LOCATION = os.getenv('LOCATION_ID', 'us-central1') +TEST_PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +TEST_LOCATION = os.getenv("LOCATION_ID", "us-central1") def test_create_job(capsys): create_result = create_job.create_scheduler_job( - TEST_PROJECT_ID, TEST_LOCATION, 'my-service') + TEST_PROJECT_ID, TEST_LOCATION, "my-service" + ) out, _ = capsys.readouterr() - assert 'Created job:' in out + assert "Created job:" in out - job_name = create_result.name.split('/')[-1] + job_name = create_result.name.split("/")[-1] create_job.delete_scheduler_job(TEST_PROJECT_ID, TEST_LOCATION, job_name) out, _ = capsys.readouterr() - assert 'Job deleted.' in out + assert "Job deleted." in out diff --git a/samples/snippets/main.py b/samples/snippets/main.py index 9d4d9753..4dad6afe 100644 --- a/samples/snippets/main.py +++ b/samples/snippets/main.py @@ -21,22 +21,24 @@ # Define relative URI for job endpoint -@app.route('/log_payload', methods=['POST']) +@app.route("/log_payload", methods=["POST"]) def example_task_handler(): """Log the job payload.""" - payload = request.get_data(as_text=True) or '(empty payload)' - print('Received job with payload: {}'.format(payload)) - return 'Printed job payload: {}'.format(payload) + payload = request.get_data(as_text=True) or "(empty payload)" + print("Received job with payload: {}".format(payload)) + return "Printed job payload: {}".format(payload) + + # [END cloud_scheduler_app] -@app.route('/') +@app.route("/") def hello(): """Basic index to verify app is serving.""" - return 'Hello World!' + return "Hello World!" -if __name__ == '__main__': +if __name__ == "__main__": # This is used when running locally. Gunicorn is used to run the # application on Google App Engine. See entrypoint in app.yaml. - app.run(host='127.0.0.1', port=8080, debug=True) + app.run(host="127.0.0.1", port=8080, debug=True) diff --git a/samples/snippets/main_test.py b/samples/snippets/main_test.py index 3d6745a5..75371c4b 100644 --- a/samples/snippets/main_test.py +++ b/samples/snippets/main_test.py @@ -18,19 +18,20 @@ @pytest.fixture def app(): import main + main.app.testing = True return main.app.test_client() def test_index(app): - r = app.get('/') + r = app.get("/") assert r.status_code == 200 def test_log_payload(capsys, app): - payload = 'test_payload' + payload = "test_payload" - r = app.post('/log_payload', data=payload) + r = app.post("/log_payload", data=payload) assert r.status_code == 200 out, _ = capsys.readouterr() @@ -38,8 +39,8 @@ def test_log_payload(capsys, app): def test_empty_payload(capsys, app): - r = app.post('/log_payload') + r = app.post("/log_payload") assert r.status_code == 200 out, _ = capsys.readouterr() - assert 'empty payload' in out + assert "empty payload" in out From 39055e99cd1ab22c88114cfac50e0c2d6626f2a0 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Thu, 11 Nov 2021 16:33:33 -0500 Subject: [PATCH 03/15] chore: assign googleapis/serverless-team as codeowner (#164) assign @googleapis/serverless-team as codeowner --- .repo-metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.repo-metadata.json b/.repo-metadata.json index 8b78b11e..beed132d 100644 --- a/.repo-metadata.json +++ b/.repo-metadata.json @@ -12,5 +12,5 @@ "api_id": "cloudscheduler.googleapis.com", "requires_billing": true, "default_version": "v1", - "codeowner_team": "" + "codeowner_team": "@googleapis/serverless-team" } From 070f283082b002648967dea2df5572a583d0d493 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 11 Nov 2021 18:33:59 -0500 Subject: [PATCH 04/15] chore(python): add .github/CODEOWNERS as a templated file (#163) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(python): add .github/CODEOWNERS as a templated file Source-Link: https://github.com/googleapis/synthtool/commit/c5026b3217973a8db55db8ee85feee0e9a65e295 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:0e18b9475fbeb12d9ad4302283171edebb6baf2dfca1bd215ee3b34ed79d95d7 * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- .github/.OwlBot.lock.yaml | 2 +- .github/CODEOWNERS | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 63bf76ea..7519fa3a 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:39ad8c0570e4f5d2d3124a509de4fe975e799e2b97e0f58aed88f8880d5a8b60 + digest: sha256:0e18b9475fbeb12d9ad4302283171edebb6baf2dfca1bd215ee3b34ed79d95d7 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0615704c..a05a94c3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,10 +3,10 @@ # # For syntax help see: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax +# Note: This file is autogenerated. To make changes to the codeowner team, please update .repo-metadata.json. -# The @googleapis/yoshi-python is the default owner for changes in this repo -* @googleapis/yoshi-python +# @googleapis/yoshi-python @googleapis/serverless-team are the default owners for changes in this repo +* @googleapis/yoshi-python @googleapis/serverless-team - -# The python-samples-owners team is the default owner for samples -/samples/**/*.py @averikitsch @googleapis/python-samples-owners \ No newline at end of file +# @googleapis/python-samples-owners @googleapis/serverless-team are the default owners for samples changes +/samples/ @googleapis/python-samples-owners @googleapis/serverless-team From 6d6a0a47f84db3bbf45a26dbcaf98bd4c88da254 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Tue, 28 Dec 2021 13:13:59 -0500 Subject: [PATCH 05/15] chore: update .repo-metadata.json (#168) --- .repo-metadata.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.repo-metadata.json b/.repo-metadata.json index beed132d..0fded5ca 100644 --- a/.repo-metadata.json +++ b/.repo-metadata.json @@ -2,9 +2,9 @@ "name": "cloudscheduler", "name_pretty": "Google Cloud Scheduler", "product_documentation": "https://cloud.google.com/scheduler/docs", - "client_documentation": "https://googleapis.dev/python/cloudscheduler/latest", + "client_documentation": "https://cloud.google.com/python/docs/reference/cloudscheduler/latest", "issue_tracker": "https://issuetracker.google.com/savedsearches/5411429", - "release_level": "ga", + "release_level": "stable", "language": "python", "library_type": "GAPIC_AUTO", "repo": "googleapis/python-scheduler", @@ -12,5 +12,6 @@ "api_id": "cloudscheduler.googleapis.com", "requires_billing": true, "default_version": "v1", - "codeowner_team": "@googleapis/serverless-team" + "codeowner_team": "@googleapis/serverless-team", + "api_shortname": "cloudscheduler" } From 8681b1f012616e4d254caec9218d5af77413364f Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 6 Jan 2022 17:12:16 +0000 Subject: [PATCH 06/15] chore: use python-samples-reviewers (#170) --- .github/.OwlBot.lock.yaml | 2 +- .github/CODEOWNERS | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 7519fa3a..f33299dd 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:0e18b9475fbeb12d9ad4302283171edebb6baf2dfca1bd215ee3b34ed79d95d7 + digest: sha256:899d5d7cc340fa8ef9d8ae1a8cfba362c6898584f779e156f25ee828ba824610 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a05a94c3..25128855 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,5 +8,5 @@ # @googleapis/yoshi-python @googleapis/serverless-team are the default owners for changes in this repo * @googleapis/yoshi-python @googleapis/serverless-team -# @googleapis/python-samples-owners @googleapis/serverless-team are the default owners for samples changes -/samples/ @googleapis/python-samples-owners @googleapis/serverless-team +# @googleapis/python-samples-reviewers @googleapis/serverless-team are the default owners for samples changes +/samples/ @googleapis/python-samples-reviewers @googleapis/serverless-team From 42e55edf692e4e6e8644007e4beacfb811aa39c7 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Sat, 8 Jan 2022 06:15:42 -0500 Subject: [PATCH 07/15] chore: use gapic-generator-python 0.58.4 (#169) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: use gapic-generator-python 0.58.4 fix: provide appropriate mock values for message body fields committer: dovs PiperOrigin-RevId: 419025932 Source-Link: https://github.com/googleapis/googleapis/commit/73da6697f598f1ba30618924936a59f8e457ec89 Source-Link: https://github.com/googleapis/googleapis-gen/commit/46df624a54b9ed47c1a7eefb7a49413cf7b82f98 Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiNDZkZjYyNGE1NGI5ZWQ0N2MxYTdlZWZiN2E0OTQxM2NmN2I4MmY5OCJ9 * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot --- .../cloud_scheduler/transports/base.py | 1 - .../cloud_scheduler/transports/base.py | 1 - .../scheduler_v1/test_cloud_scheduler.py | 94 ++++++------------- .../scheduler_v1beta1/test_cloud_scheduler.py | 94 ++++++------------- 4 files changed, 62 insertions(+), 128 deletions(-) diff --git a/google/cloud/scheduler_v1/services/cloud_scheduler/transports/base.py b/google/cloud/scheduler_v1/services/cloud_scheduler/transports/base.py index ac7d4af9..9374c179 100644 --- a/google/cloud/scheduler_v1/services/cloud_scheduler/transports/base.py +++ b/google/cloud/scheduler_v1/services/cloud_scheduler/transports/base.py @@ -102,7 +102,6 @@ def __init__( credentials, _ = google.auth.load_credentials_from_file( credentials_file, **scopes_kwargs, quota_project_id=quota_project_id ) - elif credentials is None: credentials, _ = google.auth.default( **scopes_kwargs, quota_project_id=quota_project_id diff --git a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/base.py b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/base.py index 02aa59c0..7f6d60d6 100644 --- a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/base.py +++ b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/transports/base.py @@ -102,7 +102,6 @@ def __init__( credentials, _ = google.auth.load_credentials_from_file( credentials_file, **scopes_kwargs, quota_project_id=quota_project_id ) - elif credentials is None: credentials, _ = google.auth.default( **scopes_kwargs, quota_project_id=quota_project_id diff --git a/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py b/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py index 7cd4acb5..05f2b818 100644 --- a/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py +++ b/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py @@ -254,20 +254,20 @@ def test_cloud_scheduler_client_client_options( # unsupported value. with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): with pytest.raises(MutualTLSChannelError): - client = client_class() + client = client_class(transport=transport_name) # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. with mock.patch.dict( os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} ): with pytest.raises(ValueError): - client = client_class() + client = client_class(transport=transport_name) # Check the case quota_project_id is provided options = client_options.ClientOptions(quota_project_id="octopus") with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None - client = client_class(transport=transport_name, client_options=options) + client = client_class(client_options=options, transport=transport_name) patched.assert_called_once_with( credentials=None, credentials_file=None, @@ -326,7 +326,7 @@ def test_cloud_scheduler_client_mtls_env_auto( ) with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None - client = client_class(transport=transport_name, client_options=options) + client = client_class(client_options=options, transport=transport_name) if use_client_cert_env == "false": expected_client_cert_source = None @@ -421,7 +421,7 @@ def test_cloud_scheduler_client_client_options_scopes( options = client_options.ClientOptions(scopes=["1", "2"],) with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None - client = client_class(transport=transport_name, client_options=options) + client = client_class(client_options=options, transport=transport_name) patched.assert_called_once_with( credentials=None, credentials_file=None, @@ -452,7 +452,7 @@ def test_cloud_scheduler_client_client_options_credentials_file( options = client_options.ClientOptions(credentials_file="credentials.json") with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None - client = client_class(transport=transport_name, client_options=options) + client = client_class(client_options=options, transport=transport_name) patched.assert_called_once_with( credentials=None, credentials_file="credentials.json", @@ -485,9 +485,8 @@ def test_cloud_scheduler_client_client_options_from_dict(): ) -def test_list_jobs( - transport: str = "grpc", request_type=cloudscheduler.ListJobsRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.ListJobsRequest, dict,]) +def test_list_jobs(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -514,10 +513,6 @@ def test_list_jobs( assert response.next_page_token == "next_page_token_value" -def test_list_jobs_from_dict(): - test_list_jobs(request_type=dict) - - def test_list_jobs_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -693,8 +688,10 @@ async def test_list_jobs_flattened_error_async(): ) -def test_list_jobs_pager(): - client = CloudSchedulerClient(credentials=ga_credentials.AnonymousCredentials,) +def test_list_jobs_pager(transport_name: str = "grpc"): + client = CloudSchedulerClient( + credentials=ga_credentials.AnonymousCredentials, transport=transport_name, + ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: @@ -722,8 +719,10 @@ def test_list_jobs_pager(): assert all(isinstance(i, job.Job) for i in results) -def test_list_jobs_pages(): - client = CloudSchedulerClient(credentials=ga_credentials.AnonymousCredentials,) +def test_list_jobs_pages(transport_name: str = "grpc"): + client = CloudSchedulerClient( + credentials=ga_credentials.AnonymousCredentials, transport=transport_name, + ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: @@ -795,7 +794,8 @@ async def test_list_jobs_async_pages(): assert page_.raw_page.next_page_token == token -def test_get_job(transport: str = "grpc", request_type=cloudscheduler.GetJobRequest): +@pytest.mark.parametrize("request_type", [cloudscheduler.GetJobRequest, dict,]) +def test_get_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -831,10 +831,6 @@ def test_get_job(transport: str = "grpc", request_type=cloudscheduler.GetJobRequ assert response.state == job.Job.State.ENABLED -def test_get_job_from_dict(): - test_get_job(request_type=dict) - - def test_get_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -1016,9 +1012,8 @@ async def test_get_job_flattened_error_async(): ) -def test_create_job( - transport: str = "grpc", request_type=cloudscheduler.CreateJobRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.CreateJobRequest, dict,]) +def test_create_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -1054,10 +1049,6 @@ def test_create_job( assert response.state == gcs_job.Job.State.ENABLED -def test_create_job_from_dict(): - test_create_job(request_type=dict) - - def test_create_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -1253,9 +1244,8 @@ async def test_create_job_flattened_error_async(): ) -def test_update_job( - transport: str = "grpc", request_type=cloudscheduler.UpdateJobRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.UpdateJobRequest, dict,]) +def test_update_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -1291,10 +1281,6 @@ def test_update_job( assert response.state == gcs_job.Job.State.ENABLED -def test_update_job_from_dict(): - test_update_job(request_type=dict) - - def test_update_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -1492,9 +1478,8 @@ async def test_update_job_flattened_error_async(): ) -def test_delete_job( - transport: str = "grpc", request_type=cloudscheduler.DeleteJobRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.DeleteJobRequest, dict,]) +def test_delete_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -1518,10 +1503,6 @@ def test_delete_job( assert response is None -def test_delete_job_from_dict(): - test_delete_job(request_type=dict) - - def test_delete_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -1690,9 +1671,8 @@ async def test_delete_job_flattened_error_async(): ) -def test_pause_job( - transport: str = "grpc", request_type=cloudscheduler.PauseJobRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.PauseJobRequest, dict,]) +def test_pause_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -1728,10 +1708,6 @@ def test_pause_job( assert response.state == job.Job.State.ENABLED -def test_pause_job_from_dict(): - test_pause_job(request_type=dict) - - def test_pause_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -1913,9 +1889,8 @@ async def test_pause_job_flattened_error_async(): ) -def test_resume_job( - transport: str = "grpc", request_type=cloudscheduler.ResumeJobRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.ResumeJobRequest, dict,]) +def test_resume_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -1951,10 +1926,6 @@ def test_resume_job( assert response.state == job.Job.State.ENABLED -def test_resume_job_from_dict(): - test_resume_job(request_type=dict) - - def test_resume_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -2136,7 +2107,8 @@ async def test_resume_job_flattened_error_async(): ) -def test_run_job(transport: str = "grpc", request_type=cloudscheduler.RunJobRequest): +@pytest.mark.parametrize("request_type", [cloudscheduler.RunJobRequest, dict,]) +def test_run_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -2172,10 +2144,6 @@ def test_run_job(transport: str = "grpc", request_type=cloudscheduler.RunJobRequ assert response.state == job.Job.State.ENABLED -def test_run_job_from_dict(): - test_run_job(request_type=dict) - - def test_run_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -2898,7 +2866,7 @@ def test_parse_common_location_path(): assert expected == actual -def test_client_withDEFAULT_CLIENT_INFO(): +def test_client_with_default_client_info(): client_info = gapic_v1.client_info.ClientInfo() with mock.patch.object( diff --git a/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py b/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py index 091ca064..826c7e74 100644 --- a/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py +++ b/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py @@ -256,20 +256,20 @@ def test_cloud_scheduler_client_client_options( # unsupported value. with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): with pytest.raises(MutualTLSChannelError): - client = client_class() + client = client_class(transport=transport_name) # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. with mock.patch.dict( os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} ): with pytest.raises(ValueError): - client = client_class() + client = client_class(transport=transport_name) # Check the case quota_project_id is provided options = client_options.ClientOptions(quota_project_id="octopus") with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None - client = client_class(transport=transport_name, client_options=options) + client = client_class(client_options=options, transport=transport_name) patched.assert_called_once_with( credentials=None, credentials_file=None, @@ -328,7 +328,7 @@ def test_cloud_scheduler_client_mtls_env_auto( ) with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None - client = client_class(transport=transport_name, client_options=options) + client = client_class(client_options=options, transport=transport_name) if use_client_cert_env == "false": expected_client_cert_source = None @@ -423,7 +423,7 @@ def test_cloud_scheduler_client_client_options_scopes( options = client_options.ClientOptions(scopes=["1", "2"],) with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None - client = client_class(transport=transport_name, client_options=options) + client = client_class(client_options=options, transport=transport_name) patched.assert_called_once_with( credentials=None, credentials_file=None, @@ -454,7 +454,7 @@ def test_cloud_scheduler_client_client_options_credentials_file( options = client_options.ClientOptions(credentials_file="credentials.json") with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None - client = client_class(transport=transport_name, client_options=options) + client = client_class(client_options=options, transport=transport_name) patched.assert_called_once_with( credentials=None, credentials_file="credentials.json", @@ -487,9 +487,8 @@ def test_cloud_scheduler_client_client_options_from_dict(): ) -def test_list_jobs( - transport: str = "grpc", request_type=cloudscheduler.ListJobsRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.ListJobsRequest, dict,]) +def test_list_jobs(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -516,10 +515,6 @@ def test_list_jobs( assert response.next_page_token == "next_page_token_value" -def test_list_jobs_from_dict(): - test_list_jobs(request_type=dict) - - def test_list_jobs_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -695,8 +690,10 @@ async def test_list_jobs_flattened_error_async(): ) -def test_list_jobs_pager(): - client = CloudSchedulerClient(credentials=ga_credentials.AnonymousCredentials,) +def test_list_jobs_pager(transport_name: str = "grpc"): + client = CloudSchedulerClient( + credentials=ga_credentials.AnonymousCredentials, transport=transport_name, + ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: @@ -724,8 +721,10 @@ def test_list_jobs_pager(): assert all(isinstance(i, job.Job) for i in results) -def test_list_jobs_pages(): - client = CloudSchedulerClient(credentials=ga_credentials.AnonymousCredentials,) +def test_list_jobs_pages(transport_name: str = "grpc"): + client = CloudSchedulerClient( + credentials=ga_credentials.AnonymousCredentials, transport=transport_name, + ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: @@ -797,7 +796,8 @@ async def test_list_jobs_async_pages(): assert page_.raw_page.next_page_token == token -def test_get_job(transport: str = "grpc", request_type=cloudscheduler.GetJobRequest): +@pytest.mark.parametrize("request_type", [cloudscheduler.GetJobRequest, dict,]) +def test_get_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -833,10 +833,6 @@ def test_get_job(transport: str = "grpc", request_type=cloudscheduler.GetJobRequ assert response.state == job.Job.State.ENABLED -def test_get_job_from_dict(): - test_get_job(request_type=dict) - - def test_get_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -1018,9 +1014,8 @@ async def test_get_job_flattened_error_async(): ) -def test_create_job( - transport: str = "grpc", request_type=cloudscheduler.CreateJobRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.CreateJobRequest, dict,]) +def test_create_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -1056,10 +1051,6 @@ def test_create_job( assert response.state == gcs_job.Job.State.ENABLED -def test_create_job_from_dict(): - test_create_job(request_type=dict) - - def test_create_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -1255,9 +1246,8 @@ async def test_create_job_flattened_error_async(): ) -def test_update_job( - transport: str = "grpc", request_type=cloudscheduler.UpdateJobRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.UpdateJobRequest, dict,]) +def test_update_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -1293,10 +1283,6 @@ def test_update_job( assert response.state == gcs_job.Job.State.ENABLED -def test_update_job_from_dict(): - test_update_job(request_type=dict) - - def test_update_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -1494,9 +1480,8 @@ async def test_update_job_flattened_error_async(): ) -def test_delete_job( - transport: str = "grpc", request_type=cloudscheduler.DeleteJobRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.DeleteJobRequest, dict,]) +def test_delete_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -1520,10 +1505,6 @@ def test_delete_job( assert response is None -def test_delete_job_from_dict(): - test_delete_job(request_type=dict) - - def test_delete_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -1692,9 +1673,8 @@ async def test_delete_job_flattened_error_async(): ) -def test_pause_job( - transport: str = "grpc", request_type=cloudscheduler.PauseJobRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.PauseJobRequest, dict,]) +def test_pause_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -1730,10 +1710,6 @@ def test_pause_job( assert response.state == job.Job.State.ENABLED -def test_pause_job_from_dict(): - test_pause_job(request_type=dict) - - def test_pause_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -1915,9 +1891,8 @@ async def test_pause_job_flattened_error_async(): ) -def test_resume_job( - transport: str = "grpc", request_type=cloudscheduler.ResumeJobRequest -): +@pytest.mark.parametrize("request_type", [cloudscheduler.ResumeJobRequest, dict,]) +def test_resume_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -1953,10 +1928,6 @@ def test_resume_job( assert response.state == job.Job.State.ENABLED -def test_resume_job_from_dict(): - test_resume_job(request_type=dict) - - def test_resume_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -2138,7 +2109,8 @@ async def test_resume_job_flattened_error_async(): ) -def test_run_job(transport: str = "grpc", request_type=cloudscheduler.RunJobRequest): +@pytest.mark.parametrize("request_type", [cloudscheduler.RunJobRequest, dict,]) +def test_run_job(request_type, transport: str = "grpc"): client = CloudSchedulerClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) @@ -2174,10 +2146,6 @@ def test_run_job(transport: str = "grpc", request_type=cloudscheduler.RunJobRequ assert response.state == job.Job.State.ENABLED -def test_run_job_from_dict(): - test_run_job(request_type=dict) - - def test_run_job_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @@ -2900,7 +2868,7 @@ def test_parse_common_location_path(): assert expected == actual -def test_client_withDEFAULT_CLIENT_INFO(): +def test_client_with_default_client_info(): client_info = gapic_v1.client_info.ClientInfo() with mock.patch.object( From 2b13b271ff31b089fcd8cdedf9dea45c2a82f6f2 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 07:48:02 -0500 Subject: [PATCH 08/15] chore(samples): Add check for tests in directory (#172) Source-Link: https://github.com/googleapis/synthtool/commit/52aef91f8d25223d9dbdb4aebd94ba8eea2101f3 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:36a95b8f494e4674dc9eee9af98961293b51b86b3649942aac800ae6c1f796d4 Co-authored-by: Owl Bot --- .github/.OwlBot.lock.yaml | 2 +- samples/snippets/noxfile.py | 70 +++++++++++++++++++++---------------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index f33299dd..6b8a73b3 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:899d5d7cc340fa8ef9d8ae1a8cfba362c6898584f779e156f25ee828ba824610 + digest: sha256:36a95b8f494e4674dc9eee9af98961293b51b86b3649942aac800ae6c1f796d4 diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index 93a9122c..3bbef5d5 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -14,6 +14,7 @@ from __future__ import print_function +import glob import os from pathlib import Path import sys @@ -184,37 +185,44 @@ def blacken(session: nox.sessions.Session) -> None: def _session_tests( session: nox.sessions.Session, post_install: Callable = None ) -> None: - if TEST_CONFIG["pip_version_override"]: - pip_version = TEST_CONFIG["pip_version_override"] - session.install(f"pip=={pip_version}") - """Runs py.test for a particular project.""" - if os.path.exists("requirements.txt"): - if os.path.exists("constraints.txt"): - session.install("-r", "requirements.txt", "-c", "constraints.txt") - else: - session.install("-r", "requirements.txt") - - if os.path.exists("requirements-test.txt"): - if os.path.exists("constraints-test.txt"): - session.install("-r", "requirements-test.txt", "-c", "constraints-test.txt") - else: - session.install("-r", "requirements-test.txt") - - if INSTALL_LIBRARY_FROM_SOURCE: - session.install("-e", _get_repo_root()) - - if post_install: - post_install(session) - - session.run( - "pytest", - *(PYTEST_COMMON_ARGS + session.posargs), - # Pytest will return 5 when no tests are collected. This can happen - # on travis where slow and flaky tests are excluded. - # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html - success_codes=[0, 5], - env=get_pytest_env_vars(), - ) + # check for presence of tests + test_list = glob.glob("*_test.py") + glob.glob("test_*.py") + if len(test_list) == 0: + print("No tests found, skipping directory.") + else: + if TEST_CONFIG["pip_version_override"]: + pip_version = TEST_CONFIG["pip_version_override"] + session.install(f"pip=={pip_version}") + """Runs py.test for a particular project.""" + if os.path.exists("requirements.txt"): + if os.path.exists("constraints.txt"): + session.install("-r", "requirements.txt", "-c", "constraints.txt") + else: + session.install("-r", "requirements.txt") + + if os.path.exists("requirements-test.txt"): + if os.path.exists("constraints-test.txt"): + session.install( + "-r", "requirements-test.txt", "-c", "constraints-test.txt" + ) + else: + session.install("-r", "requirements-test.txt") + + if INSTALL_LIBRARY_FROM_SOURCE: + session.install("-e", _get_repo_root()) + + if post_install: + post_install(session) + + session.run( + "pytest", + *(PYTEST_COMMON_ARGS + session.posargs), + # Pytest will return 5 when no tests are collected. This can happen + # on travis where slow and flaky tests are excluded. + # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html + success_codes=[0, 5], + env=get_pytest_env_vars(), + ) @nox.session(python=ALL_VERSIONS) From dd77b38449c809b84694e76fc2878a3d5d51e62b Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Fri, 14 Jan 2022 16:08:13 +0000 Subject: [PATCH 09/15] chore(python): update release.sh to use keystore (#174) build: switch to release-please for tagging --- .github/.OwlBot.lock.yaml | 2 +- .github/release-please.yml | 1 + .github/release-trigger.yml | 1 + .kokoro/release.sh | 2 +- .kokoro/release/common.cfg | 12 +++++++++++- 5 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 .github/release-trigger.yml diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 6b8a73b3..eecb84c2 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:36a95b8f494e4674dc9eee9af98961293b51b86b3649942aac800ae6c1f796d4 + digest: sha256:ae600f36b6bc972b368367b6f83a1d91ec2c82a4a116b383d67d547c56fe6de3 diff --git a/.github/release-please.yml b/.github/release-please.yml index 4507ad05..466597e5 100644 --- a/.github/release-please.yml +++ b/.github/release-please.yml @@ -1 +1,2 @@ releaseType: python +handleGHRelease: true diff --git a/.github/release-trigger.yml b/.github/release-trigger.yml new file mode 100644 index 00000000..d4ca9418 --- /dev/null +++ b/.github/release-trigger.yml @@ -0,0 +1 @@ +enabled: true diff --git a/.kokoro/release.sh b/.kokoro/release.sh index dc83fecb..5b18b519 100755 --- a/.kokoro/release.sh +++ b/.kokoro/release.sh @@ -26,7 +26,7 @@ python3 -m pip install --upgrade twine wheel setuptools export PYTHONUNBUFFERED=1 # Move into the package, build the distribution and upload. -TWINE_PASSWORD=$(cat "${KOKORO_GFILE_DIR}/secret_manager/google-cloud-pypi-token") +TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google-cloud-pypi-token-keystore-1") cd github/python-scheduler python3 setup.py sdist bdist_wheel twine upload --username __token__ --password "${TWINE_PASSWORD}" dist/* diff --git a/.kokoro/release/common.cfg b/.kokoro/release/common.cfg index fda66722..44d0079c 100644 --- a/.kokoro/release/common.cfg +++ b/.kokoro/release/common.cfg @@ -23,8 +23,18 @@ env_vars: { value: "github/python-scheduler/.kokoro/release.sh" } +# Fetch PyPI password +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 73713 + keyname: "google-cloud-pypi-token-keystore-1" + } + } +} + # Tokens needed to report release status back to GitHub env_vars: { key: "SECRET_MANAGER_KEYS" - value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem,google-cloud-pypi-token" + value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem" } From e6c642c19037c626c47970fcc5b0b565850df1ce Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 18 Jan 2022 20:30:23 -0500 Subject: [PATCH 10/15] chore(python): Noxfile recognizes that tests can live in a folder (#176) Source-Link: https://github.com/googleapis/synthtool/commit/4760d8dce1351d93658cb11d02a1b7ceb23ae5d7 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:f0e4b51deef56bed74d3e2359c583fc104a8d6367da3984fc5c66938db738828 Co-authored-by: Owl Bot --- .github/.OwlBot.lock.yaml | 2 +- samples/snippets/noxfile.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index eecb84c2..52d79c11 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:ae600f36b6bc972b368367b6f83a1d91ec2c82a4a116b383d67d547c56fe6de3 + digest: sha256:f0e4b51deef56bed74d3e2359c583fc104a8d6367da3984fc5c66938db738828 diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index 3bbef5d5..20cdfc62 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -187,6 +187,7 @@ def _session_tests( ) -> None: # check for presence of tests test_list = glob.glob("*_test.py") + glob.glob("test_*.py") + test_list.extend(glob.glob("tests")) if len(test_list) == 0: print("No tests found, skipping directory.") else: From 865f06c342e70335179051abf7a823a8f51e7efc Mon Sep 17 00:00:00 2001 From: Dina Graves Portman Date: Thu, 20 Jan 2022 10:56:25 -0500 Subject: [PATCH 11/15] chore: update codeowners (#177) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: update codeowners * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot --- .github/CODEOWNERS | 8 ++++---- .repo-metadata.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 25128855..63a84c3b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,8 +5,8 @@ # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax # Note: This file is autogenerated. To make changes to the codeowner team, please update .repo-metadata.json. -# @googleapis/yoshi-python @googleapis/serverless-team are the default owners for changes in this repo -* @googleapis/yoshi-python @googleapis/serverless-team +# @googleapis/yoshi-python @googleapis/aap-dpes are the default owners for changes in this repo +* @googleapis/yoshi-python @googleapis/aap-dpes -# @googleapis/python-samples-reviewers @googleapis/serverless-team are the default owners for samples changes -/samples/ @googleapis/python-samples-reviewers @googleapis/serverless-team +# @googleapis/python-samples-reviewers @googleapis/aap-dpes are the default owners for samples changes +/samples/ @googleapis/python-samples-reviewers @googleapis/aap-dpes diff --git a/.repo-metadata.json b/.repo-metadata.json index 0fded5ca..aa0bd2f1 100644 --- a/.repo-metadata.json +++ b/.repo-metadata.json @@ -12,6 +12,6 @@ "api_id": "cloudscheduler.googleapis.com", "requires_billing": true, "default_version": "v1", - "codeowner_team": "@googleapis/serverless-team", + "codeowner_team": "@googleapis/aap-dpes", "api_shortname": "cloudscheduler" } From 4cc52d12bfcb044323e179b1584d7ed68da2672c Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 20 Jan 2022 14:17:38 -0500 Subject: [PATCH 12/15] ci(python): run lint / unit tests / docs as GH actions (#178) * ci(python): run lint / unit tests / docs as GH actions Source-Link: https://github.com/googleapis/synthtool/commit/57be0cdb0b94e1669cee0ca38d790de1dfdbcd44 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:ed1f9983d5a935a89fe8085e8bb97d94e41015252c5b6c9771257cf8624367e6 * add commit to trigger gh actions Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- .github/.OwlBot.lock.yaml | 16 +++++++++- .github/workflows/docs.yml | 38 +++++++++++++++++++++++ .github/workflows/lint.yml | 25 +++++++++++++++ .github/workflows/unittest.yml | 57 ++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/docs.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/unittest.yml diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 52d79c11..b668c04d 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -1,3 +1,17 @@ +# Copyright 2022 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 +# +# 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. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:f0e4b51deef56bed74d3e2359c583fc104a8d6367da3984fc5c66938db738828 + digest: sha256:ed1f9983d5a935a89fe8085e8bb97d94e41015252c5b6c9771257cf8624367e6 + diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..f7b8344c --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,38 @@ +on: + pull_request: + branches: + - main +name: docs +jobs: + docs: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install nox + run: | + python -m pip install --upgrade setuptools pip wheel + python -m pip install nox + - name: Run docs + run: | + nox -s docs + docfx: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install nox + run: | + python -m pip install --upgrade setuptools pip wheel + python -m pip install nox + - name: Run docfx + run: | + nox -s docfx diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..1e8b05c3 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,25 @@ +on: + pull_request: + branches: + - main +name: lint +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install nox + run: | + python -m pip install --upgrade setuptools pip wheel + python -m pip install nox + - name: Run lint + run: | + nox -s lint + - name: Run lint_setup_py + run: | + nox -s lint_setup_py diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml new file mode 100644 index 00000000..074ee250 --- /dev/null +++ b/.github/workflows/unittest.yml @@ -0,0 +1,57 @@ +on: + pull_request: + branches: + - main +name: unittest +jobs: + unit: + runs-on: ubuntu-latest + strategy: + matrix: + python: ['3.6', '3.7', '3.8', '3.9', '3.10'] + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + - name: Install nox + run: | + python -m pip install --upgrade setuptools pip wheel + python -m pip install nox + - name: Run unit tests + env: + COVERAGE_FILE: .coverage-${{ matrix.python }} + run: | + nox -s unit-${{ matrix.python }} + - name: Upload coverage results + uses: actions/upload-artifact@v2 + with: + name: coverage-artifacts + path: .coverage-${{ matrix.python }} + + cover: + runs-on: ubuntu-latest + needs: + - unit + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install coverage + run: | + python -m pip install --upgrade setuptools pip wheel + python -m pip install coverage + - name: Download coverage results + uses: actions/download-artifact@v2 + with: + name: coverage-artifacts + path: .coverage-results/ + - name: Report coverage results + run: | + coverage combine .coverage-results/.coverage* + coverage report --show-missing --fail-under=100 From 4f61c234ccc8267e1dd998a70231130497b7db25 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Mon, 24 Jan 2022 13:09:12 -0700 Subject: [PATCH 13/15] chore: make samples 3.6 check optional (#179) --- .github/sync-repo-settings.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index 3e98ae70..37438d33 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -10,6 +10,5 @@ branchProtectionRules: - 'Kokoro' - 'cla/google' - 'Samples - Lint' - - 'Samples - Python 3.6' - 'Samples - Python 3.7' - 'Samples - Python 3.8' From 74eaf8b00c684c476d7a9f271880e83fc67dedac Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 25 Jan 2022 12:43:53 -0500 Subject: [PATCH 14/15] feat: add api key support (#180) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: upgrade gapic-generator-java, gax-java and gapic-generator-python PiperOrigin-RevId: 423842556 Source-Link: https://github.com/googleapis/googleapis/commit/a616ca08f4b1416abbac7bc5dd6d61c791756a81 Source-Link: https://github.com/googleapis/googleapis-gen/commit/29b938c58c1e51d019f2ee539d55dc0a3c86a905 Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiMjliOTM4YzU4YzFlNTFkMDE5ZjJlZTUzOWQ1NWRjMGEzYzg2YTkwNSJ9 * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot --- .../services/cloud_scheduler/async_client.py | 38 +++++- .../services/cloud_scheduler/client.py | 127 +++++++++++------ .../services/cloud_scheduler/async_client.py | 38 +++++- .../services/cloud_scheduler/client.py | 127 +++++++++++------ .../scheduler_v1/test_cloud_scheduler.py | 128 ++++++++++++++++++ .../scheduler_v1beta1/test_cloud_scheduler.py | 128 ++++++++++++++++++ 6 files changed, 498 insertions(+), 88 deletions(-) diff --git a/google/cloud/scheduler_v1/services/cloud_scheduler/async_client.py b/google/cloud/scheduler_v1/services/cloud_scheduler/async_client.py index e7e997e2..8c33d727 100644 --- a/google/cloud/scheduler_v1/services/cloud_scheduler/async_client.py +++ b/google/cloud/scheduler_v1/services/cloud_scheduler/async_client.py @@ -16,7 +16,7 @@ from collections import OrderedDict import functools import re -from typing import Dict, Sequence, Tuple, Type, Union +from typing import Dict, Optional, Sequence, Tuple, Type, Union import pkg_resources from google.api_core.client_options import ClientOptions @@ -117,6 +117,42 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): from_service_account_json = from_service_account_file + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + return CloudSchedulerClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore + @property def transport(self) -> CloudSchedulerTransport: """Returns the transport used by the client instance. diff --git a/google/cloud/scheduler_v1/services/cloud_scheduler/client.py b/google/cloud/scheduler_v1/services/cloud_scheduler/client.py index 938b6905..0da1da75 100644 --- a/google/cloud/scheduler_v1/services/cloud_scheduler/client.py +++ b/google/cloud/scheduler_v1/services/cloud_scheduler/client.py @@ -254,6 +254,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]: m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) return m.groupdict() if m else {} + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[client_options_lib.ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + if client_options is None: + client_options = client_options_lib.ClientOptions() + use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_client_cert not in ("true", "false"): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + if use_mtls_endpoint not in ("auto", "never", "always"): + raise MutualTLSChannelError( + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" + ) + + # Figure out the client cert source to use. + client_cert_source = None + if use_client_cert == "true": + if client_options.client_cert_source: + client_cert_source = client_options.client_cert_source + elif mtls.has_default_client_cert_source(): + client_cert_source = mtls.default_client_cert_source() + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + elif use_mtls_endpoint == "always" or ( + use_mtls_endpoint == "auto" and client_cert_source + ): + api_endpoint = cls.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = cls.DEFAULT_ENDPOINT + + return api_endpoint, client_cert_source + def __init__( self, *, @@ -304,57 +371,22 @@ def __init__( if client_options is None: client_options = client_options_lib.ClientOptions() - # Create SSL credentials for mutual TLS if needed. - if os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") not in ( - "true", - "false", - ): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - use_client_cert = ( - os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true" + api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( + client_options ) - client_cert_source_func = None - is_mtls = False - if use_client_cert: - if client_options.client_cert_source: - is_mtls = True - client_cert_source_func = client_options.client_cert_source - else: - is_mtls = mtls.has_default_client_cert_source() - if is_mtls: - client_cert_source_func = mtls.default_client_cert_source() - else: - client_cert_source_func = None - - # Figure out which api endpoint to use. - if client_options.api_endpoint is not None: - api_endpoint = client_options.api_endpoint - else: - use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") - if use_mtls_env == "never": - api_endpoint = self.DEFAULT_ENDPOINT - elif use_mtls_env == "always": - api_endpoint = self.DEFAULT_MTLS_ENDPOINT - elif use_mtls_env == "auto": - if is_mtls: - api_endpoint = self.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = self.DEFAULT_ENDPOINT - else: - raise MutualTLSChannelError( - "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted " - "values: never, auto, always" - ) + api_key_value = getattr(client_options, "api_key", None) + if api_key_value and credentials: + raise ValueError( + "client_options.api_key and credentials are mutually exclusive" + ) # Save or instantiate the transport. # Ordinarily, we provide the transport, but allowing a custom transport # instance provides an extensibility point for unusual situations. if isinstance(transport, CloudSchedulerTransport): # transport is a CloudSchedulerTransport instance. - if credentials or client_options.credentials_file: + if credentials or client_options.credentials_file or api_key_value: raise ValueError( "When providing a transport instance, " "provide its credentials directly." @@ -366,6 +398,15 @@ def __init__( ) self._transport = transport else: + import google.auth._default # type: ignore + + if api_key_value and hasattr( + google.auth._default, "get_api_key_credentials" + ): + credentials = google.auth._default.get_api_key_credentials( + api_key_value + ) + Transport = type(self).get_transport_class(transport) self._transport = Transport( credentials=credentials, diff --git a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/async_client.py b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/async_client.py index 913d832a..bc065446 100644 --- a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/async_client.py +++ b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/async_client.py @@ -16,7 +16,7 @@ from collections import OrderedDict import functools import re -from typing import Dict, Sequence, Tuple, Type, Union +from typing import Dict, Optional, Sequence, Tuple, Type, Union import pkg_resources from google.api_core.client_options import ClientOptions @@ -117,6 +117,42 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): from_service_account_json = from_service_account_file + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + return CloudSchedulerClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore + @property def transport(self) -> CloudSchedulerTransport: """Returns the transport used by the client instance. diff --git a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py index e0a9c803..a6ac7814 100644 --- a/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py +++ b/google/cloud/scheduler_v1beta1/services/cloud_scheduler/client.py @@ -254,6 +254,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]: m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) return m.groupdict() if m else {} + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[client_options_lib.ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + if client_options is None: + client_options = client_options_lib.ClientOptions() + use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_client_cert not in ("true", "false"): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + if use_mtls_endpoint not in ("auto", "never", "always"): + raise MutualTLSChannelError( + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" + ) + + # Figure out the client cert source to use. + client_cert_source = None + if use_client_cert == "true": + if client_options.client_cert_source: + client_cert_source = client_options.client_cert_source + elif mtls.has_default_client_cert_source(): + client_cert_source = mtls.default_client_cert_source() + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + elif use_mtls_endpoint == "always" or ( + use_mtls_endpoint == "auto" and client_cert_source + ): + api_endpoint = cls.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = cls.DEFAULT_ENDPOINT + + return api_endpoint, client_cert_source + def __init__( self, *, @@ -304,57 +371,22 @@ def __init__( if client_options is None: client_options = client_options_lib.ClientOptions() - # Create SSL credentials for mutual TLS if needed. - if os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") not in ( - "true", - "false", - ): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - use_client_cert = ( - os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true" + api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( + client_options ) - client_cert_source_func = None - is_mtls = False - if use_client_cert: - if client_options.client_cert_source: - is_mtls = True - client_cert_source_func = client_options.client_cert_source - else: - is_mtls = mtls.has_default_client_cert_source() - if is_mtls: - client_cert_source_func = mtls.default_client_cert_source() - else: - client_cert_source_func = None - - # Figure out which api endpoint to use. - if client_options.api_endpoint is not None: - api_endpoint = client_options.api_endpoint - else: - use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") - if use_mtls_env == "never": - api_endpoint = self.DEFAULT_ENDPOINT - elif use_mtls_env == "always": - api_endpoint = self.DEFAULT_MTLS_ENDPOINT - elif use_mtls_env == "auto": - if is_mtls: - api_endpoint = self.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = self.DEFAULT_ENDPOINT - else: - raise MutualTLSChannelError( - "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted " - "values: never, auto, always" - ) + api_key_value = getattr(client_options, "api_key", None) + if api_key_value and credentials: + raise ValueError( + "client_options.api_key and credentials are mutually exclusive" + ) # Save or instantiate the transport. # Ordinarily, we provide the transport, but allowing a custom transport # instance provides an extensibility point for unusual situations. if isinstance(transport, CloudSchedulerTransport): # transport is a CloudSchedulerTransport instance. - if credentials or client_options.credentials_file: + if credentials or client_options.credentials_file or api_key_value: raise ValueError( "When providing a transport instance, " "provide its credentials directly." @@ -366,6 +398,15 @@ def __init__( ) self._transport = transport else: + import google.auth._default # type: ignore + + if api_key_value and hasattr( + google.auth._default, "get_api_key_credentials" + ): + credentials = google.auth._default.get_api_key_credentials( + api_key_value + ) + Transport = type(self).get_transport_class(transport) self._transport = Transport( credentials=credentials, diff --git a/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py b/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py index 05f2b818..f42acb46 100644 --- a/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py +++ b/tests/unit/gapic/scheduler_v1/test_cloud_scheduler.py @@ -403,6 +403,87 @@ def test_cloud_scheduler_client_mtls_env_auto( ) +@pytest.mark.parametrize( + "client_class", [CloudSchedulerClient, CloudSchedulerAsyncClient] +) +@mock.patch.object( + CloudSchedulerClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(CloudSchedulerClient), +) +@mock.patch.object( + CloudSchedulerAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(CloudSchedulerAsyncClient), +) +def test_cloud_scheduler_client_get_mtls_endpoint_and_cert_source(client_class): + mock_client_cert_source = mock.Mock() + + # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "true". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + mock_api_endpoint = "foo" + options = client_options.ClientOptions( + client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint + ) + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source( + options + ) + assert api_endpoint == mock_api_endpoint + assert cert_source == mock_client_cert_source + + # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "false". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): + mock_client_cert_source = mock.Mock() + mock_api_endpoint = "foo" + options = client_options.ClientOptions( + client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint + ) + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source( + options + ) + assert api_endpoint == mock_api_endpoint + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert doesn't exist. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert exists. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, + ): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=mock_client_cert_source, + ): + ( + api_endpoint, + cert_source, + ) = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT + assert cert_source == mock_client_cert_source + + @pytest.mark.parametrize( "client_class,transport_class,transport_name", [ @@ -2345,6 +2426,23 @@ def test_credentials_transport_error(): transport=transport, ) + # It is an error to provide an api_key and a transport instance. + transport = transports.CloudSchedulerGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = CloudSchedulerClient(client_options=options, transport=transport,) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = CloudSchedulerClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + # It is an error to provide scopes and a transport instance. transport = transports.CloudSchedulerGrpcTransport( credentials=ga_credentials.AnonymousCredentials(), @@ -2931,3 +3029,33 @@ def test_client_ctx(): with client: pass close.assert_called() + + +@pytest.mark.parametrize( + "client_class,transport_class", + [ + (CloudSchedulerClient, transports.CloudSchedulerGrpcTransport), + (CloudSchedulerAsyncClient, transports.CloudSchedulerGrpcAsyncIOTransport), + ], +) +def test_api_key_credentials(client_class, transport_class): + with mock.patch.object( + google.auth._default, "get_api_key_credentials", create=True + ) as get_api_key_credentials: + mock_cred = mock.Mock() + get_api_key_credentials.return_value = mock_cred + options = client_options.ClientOptions() + options.api_key = "api_key" + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=mock_cred, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) diff --git a/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py b/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py index 826c7e74..ab850be6 100644 --- a/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py +++ b/tests/unit/gapic/scheduler_v1beta1/test_cloud_scheduler.py @@ -405,6 +405,87 @@ def test_cloud_scheduler_client_mtls_env_auto( ) +@pytest.mark.parametrize( + "client_class", [CloudSchedulerClient, CloudSchedulerAsyncClient] +) +@mock.patch.object( + CloudSchedulerClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(CloudSchedulerClient), +) +@mock.patch.object( + CloudSchedulerAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(CloudSchedulerAsyncClient), +) +def test_cloud_scheduler_client_get_mtls_endpoint_and_cert_source(client_class): + mock_client_cert_source = mock.Mock() + + # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "true". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + mock_api_endpoint = "foo" + options = client_options.ClientOptions( + client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint + ) + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source( + options + ) + assert api_endpoint == mock_api_endpoint + assert cert_source == mock_client_cert_source + + # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "false". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): + mock_client_cert_source = mock.Mock() + mock_api_endpoint = "foo" + options = client_options.ClientOptions( + client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint + ) + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source( + options + ) + assert api_endpoint == mock_api_endpoint + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert doesn't exist. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_ENDPOINT + assert cert_source is None + + # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert exists. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, + ): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=mock_client_cert_source, + ): + ( + api_endpoint, + cert_source, + ) = client_class.get_mtls_endpoint_and_cert_source() + assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT + assert cert_source == mock_client_cert_source + + @pytest.mark.parametrize( "client_class,transport_class,transport_name", [ @@ -2347,6 +2428,23 @@ def test_credentials_transport_error(): transport=transport, ) + # It is an error to provide an api_key and a transport instance. + transport = transports.CloudSchedulerGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = CloudSchedulerClient(client_options=options, transport=transport,) + + # It is an error to provide an api_key and a credential. + options = mock.Mock() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = CloudSchedulerClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + # It is an error to provide scopes and a transport instance. transport = transports.CloudSchedulerGrpcTransport( credentials=ga_credentials.AnonymousCredentials(), @@ -2933,3 +3031,33 @@ def test_client_ctx(): with client: pass close.assert_called() + + +@pytest.mark.parametrize( + "client_class,transport_class", + [ + (CloudSchedulerClient, transports.CloudSchedulerGrpcTransport), + (CloudSchedulerAsyncClient, transports.CloudSchedulerGrpcAsyncIOTransport), + ], +) +def test_api_key_credentials(client_class, transport_class): + with mock.patch.object( + google.auth._default, "get_api_key_credentials", create=True + ) as get_api_key_credentials: + mock_cred = mock.Mock() + get_api_key_credentials.return_value = mock_cred + options = client_options.ClientOptions() + options.api_key = "api_key" + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=mock_cred, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + always_use_jwt_access=True, + ) From e35df2e21aceae05cd861ecae1bd80af3a709e6b Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 27 Jan 2022 14:45:50 -0500 Subject: [PATCH 15/15] chore(main): release 2.6.0 (#181) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac9d0f9c..40387ecd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-scheduler/#history +## [2.6.0](https://github.com/googleapis/python-scheduler/compare/v2.5.1...v2.6.0) (2022-01-25) + + +### Features + +* add api key support ([#180](https://github.com/googleapis/python-scheduler/issues/180)) ([74eaf8b](https://github.com/googleapis/python-scheduler/commit/74eaf8b00c684c476d7a9f271880e83fc67dedac)) + ### [2.5.1](https://www.github.com/googleapis/python-scheduler/compare/v2.5.0...v2.5.1) (2021-11-01) diff --git a/setup.py b/setup.py index 2e59b99f..c88fc125 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ name = "google-cloud-scheduler" description = "Cloud Scheduler API API client library" -version = "2.5.1" +version = "2.6.0" # Should be one of: # 'Development Status :: 3 - Alpha' # 'Development Status :: 4 - Beta'