diff --git a/.github/workflows/gapic-generator-tests.yml b/.github/workflows/gapic-generator-tests.yml index b9e65f1abf21..748047a7abd4 100644 --- a/.github/workflows/gapic-generator-tests.yml +++ b/.github/workflows/gapic-generator-tests.yml @@ -85,6 +85,7 @@ jobs: curl --location https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip --output /usr/src/protoc/protoc.zip cd /usr/src/protoc/ && unzip protoc.zip sudo ln -s /usr/src/protoc/bin/protoc /usr/local/bin/protoc + - name: Run Nox env: GOOGLE_SDK_PYTHON_LOGGING_SCOPE: ${{ matrix.logging_scope }} @@ -167,11 +168,13 @@ jobs: - name: Install System Deps run: sudo apt-get update && sudo apt-get install -y pandoc - name: Run Goldens (Prerelease) + env: + PRERELEASE_PYTHON: ${{ needs.python_config.outputs.prerelease_python }} run: | pip install nox cd packages/gapic-generator for pkg in credentials eventarc logging redis; do - nox -f tests/integration/goldens/$pkg/noxfile.py -s core_deps_from_source prerelease_deps + nox -f tests/integration/goldens/$pkg/noxfile.py -s core_deps_from_source-${PRERELEASE_PYTHON} prerelease_deps done fragment-snippet: @@ -201,6 +204,7 @@ jobs: curl --location https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip --output /usr/src/protoc/protoc.zip cd /usr/src/protoc/ && unzip protoc.zip sudo ln -s /usr/src/protoc/bin/protoc /usr/local/bin/protoc + - name: Run Tests run: | pip install nox @@ -232,6 +236,7 @@ jobs: # Ensure CACHE_VERSION is defined in the mono-repo secrets! key: ${{ runner.os }}-bazel-20210105-${{ secrets.CACHE_VERSION }} + - name: Run Bazel Integration Tests run: | # We need to move into the package directory if the diff --git a/.gitignore b/.gitignore index efcdb4857b95..39183b195682 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,4 @@ bazel-bin bazel-gapic-generator bazel-out bazel-testlogs +packages/gapic-generator/api-common-protos/ diff --git a/packages/gapic-generator/.python-version b/packages/gapic-generator/.python-version new file mode 100644 index 000000000000..329fd70871e4 --- /dev/null +++ b/packages/gapic-generator/.python-version @@ -0,0 +1,5 @@ +3.10.0 +3.11.0 +3.12.0 +3.13.0 +3.14.0 diff --git a/packages/gapic-generator/WORKSPACE b/packages/gapic-generator/WORKSPACE index 4da1de3cc7d4..25aa41687a0c 100644 --- a/packages/gapic-generator/WORKSPACE +++ b/packages/gapic-generator/WORKSPACE @@ -2,6 +2,31 @@ workspace(name = "gapic_generator_python") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +# Override google-api-core dependency with git archive of packages/google-api-core directory to avoid local paths +http_archive( + name = "gapic_generator_python_pip_deps_google_api_core", + urls = ["https://github.com/googleapis/google-cloud-python/archive/e0f3f85e0430e284c0cb50f0186f24c15e499707.tar.gz"], + sha256 = "bf184f6b26ed613ab0aec3453ece922e4adb5a4d4fd0a6db99ae5e0c9b371db4", + strip_prefix = "google-cloud-python-e0f3f85e0430e284c0cb50f0186f24c15e499707/packages/google-api-core", + build_file_content = """ +py_library( + name = "pkg", + srcs = glob(["google/**/*.py"]), + imports = ["."], + visibility = ["//visibility:public"], + deps = [ + "@gapic_generator_python_pip_deps_googleapis_common_protos//:pkg", + "@gapic_generator_python_pip_deps_protobuf//:pkg", + "@gapic_generator_python_pip_deps_proto_plus//:pkg", + "@gapic_generator_python_pip_deps_google_auth//:pkg", + "@gapic_generator_python_pip_deps_requests//:pkg", + ], +) +""", +) + + + _bazel_skylib_version = "1.4.0" _bazel_skylib_sha256 = "f24ab666394232f834f74d19e2ff142b0af17466ea0c69a3f4c276ee75f6efce" @@ -42,11 +67,12 @@ load("@rules_python//python:pip.bzl", "pip_parse") pip_parse( name = "gapic_generator_python_pip_deps", - requirements_lock = "//:requirements.txt", + requirements_lock = "//:requirements.txt", ) load("@gapic_generator_python_pip_deps//:requirements.bzl", "install_deps") install_deps() + # # Import gapic-generator-python specific dependencies # @@ -123,3 +149,13 @@ switched_rules_by_language( gapic = True, grpc = True, ) + +# BEGIN workaround +load("@rules_python//python:repositories.bzl", "python_register_toolchains") + +python_register_toolchains( + name = "python311", + python_version = "3.11", + ignore_root_user_error = True, +) +# END workaround diff --git a/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 b/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 index e6ffe31a47ae..2b60f5e8606d 100644 --- a/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 +++ b/packages/gapic-generator/gapic/ads-templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 @@ -103,6 +103,35 @@ def test__get_default_mtls_endpoint(): assert {{ service.client_name }}._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint +import asyncio + +@pytest.fixture(autouse=True) +def set_event_loop(): + try: + asyncio.get_running_loop() + yield + except RuntimeError: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + try: + yield + finally: + loop.close() + asyncio.set_event_loop(None) + + +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): + with mock.patch.dict( + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, + ): + yield + + @pytest.mark.parametrize("client_class,transport_name", [ {% if 'grpc' in opts.transport %} ({{ service.client_name }}, "grpc"), diff --git a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 index e2e3edb24967..3b40894acc9a 100644 --- a/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 +++ b/packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/services/%service/client.py.j2 @@ -6,6 +6,14 @@ {% import "%namespace/%name_%version/%sub/services/%service/_client_macros.j2" as macros %} {% import "%namespace/%name_%version/%sub/services/%service/_shared_macros.j2" as shared_macros %} +{% set ns = namespace(has_auto_populated=false) %} +{% for method in service.methods.values() %} + {% set method_settings = api.all_method_settings.get(method.meta.address.proto) %} + {% if method_settings is not none and method_settings.auto_populated_fields %} + {% set ns.has_auto_populated = true %} + {% endif %} +{% endfor %} + from collections import OrderedDict {% if service.any_extended_operations_methods %} import functools @@ -16,8 +24,8 @@ import logging as std_logging import os import re from typing import Dict, Callable, Mapping, MutableMapping, MutableSequence, Optional, {% if service.any_server_streaming %}Iterable, {% endif %}{% if service.any_client_streaming %}Iterator, {% endif %}Sequence, Tuple, Type, Union, cast -{% if api.all_method_settings.values()|map(attribute="auto_populated_fields", default=[])|select|list %} -import uuid +{% if ns.has_auto_populated %} +from google.api_core.gapic_v1 import _method_helpers {% endif %} import warnings @@ -30,6 +38,9 @@ from google.api_core import exceptions as core_exceptions from google.api_core import extended_operation {% endif %} from google.api_core import gapic_v1 +from google.api_core.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -154,28 +165,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = {% if service.host %}"{{ service.host }}"{% else %}None{% endif %} @@ -201,18 +191,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -365,12 +344,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = {{ service.client_name }}._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -383,13 +357,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -406,16 +374,18 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = {{ service.client_name }}._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = {{ service.client_name }}.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = {{ service.client_name }}._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + {{ service.client_name }}._DEFAULT_UNIVERSE, + {{ service.client_name }}.DEFAULT_MTLS_ENDPOINT, + {{ service.client_name }}._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -431,14 +401,11 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = {{ service.client_name }}._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + {{ service.client_name }}._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -453,7 +420,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): # NOTE (b/349488459): universe validation is disabled until further notice. return True - {% if api.all_method_settings.values()|map(attribute="auto_populated_fields", default=[])|select|list %} + {% if ns.has_auto_populated %} @staticmethod def _setup_request_id(request, field_name: str, is_proto3_optional: bool): """Populate a UUID4 field in the request if it is not already set. @@ -463,26 +430,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): field_name (str): The name of the field to populate. is_proto3_optional (bool): Whether the field is proto3 optional. """ - if isinstance(request, dict): - if is_proto3_optional: - if field_name not in request: - request[field_name] = str(uuid.uuid4()) - elif not request.get(field_name): - request[field_name] = str(uuid.uuid4()) - return - - if is_proto3_optional: - try: - # Pure protobuf messages - if not request.HasField(field_name): - setattr(request, field_name, str(uuid.uuid4())) - except (AttributeError, ValueError): - # Proto-plus messages or other objects - if field_name not in request: - setattr(request, field_name, str(uuid.uuid4())) - else: - if not getattr(request, field_name): - setattr(request, field_name, str(uuid.uuid4())) + _method_helpers.setup_request_id(request, field_name, is_proto3_optional) {% endif %} def _add_cred_info_for_auth_errors( @@ -588,12 +536,11 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta): google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/gapic/templates/noxfile.py.j2 b/packages/gapic-generator/gapic/templates/noxfile.py.j2 index 8db595319396..70155ac6f9c5 100644 --- a/packages/gapic-generator/gapic/templates/noxfile.py.j2 +++ b/packages/gapic-generator/gapic/templates/noxfile.py.j2 @@ -249,9 +249,9 @@ def install_unittest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=ALL_PYTHON) @@ -267,6 +267,16 @@ def unit(session, protobuf_implementation): ) install_unittest_dependencies(session, "-c", constraints_path) + # Override google-api-core with the local version from source if running in the monorepo + google_api_core_dir = next( + (str(p / "packages" / "google-api-core") for p in CURRENT_DIRECTORY.parents if (p / "packages" / "google-api-core").exists()), + None + ) + if google_api_core_dir: + session.run("pip", "uninstall", "google-api-core", "-y") + session.install("-e", google_api_core_dir, "--no-deps") + + # Run py.test against the unit tests. session.run( "py.test", @@ -317,9 +327,9 @@ def install_systemtest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) @@ -382,7 +392,7 @@ def cover(session): def docs(session): """Build the docs for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -415,7 +425,7 @@ def docs(session): def docfx(session): """Build the docfx yaml files for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -471,7 +481,7 @@ def prerelease_deps(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES @@ -572,7 +582,7 @@ def prerelease_deps(session, protobuf_implementation): ) -@nox.session(python=PREVIEW_PYTHON_VERSION) +@nox.session(python=ALL_PYTHON) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -583,7 +593,7 @@ def core_deps_from_source(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES diff --git a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 index c68b390b7c84..35fd0292a8d8 100644 --- a/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 +++ b/packages/gapic-generator/gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 @@ -156,186 +156,28 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert {{ service.client_name }}._get_default_mtls_endpoint(None) is None - assert {{ service.client_name }}._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert {{ service.client_name }}._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert {{ service.client_name }}._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert {{ service.client_name }}._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert {{ service.client_name }}._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert {{ service.client_name }}._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert {{ service.client_name }}._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert {{ service.client_name }}._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert {{ service.client_name }}._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - {{ service.client_name }}._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert {{ service.client_name }}._read_environment_variables() == ( - False, - "auto", - None, - ) + yield + + + - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert {{ service.client_name }}._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert {{ service.client_name }}._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert {{ service.client_name }}._read_environment_variables() == (False, "auto", None) - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - {{ service.client_name }}._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert {{ service.client_name }}._read_environment_variables() == (False, "auto", "foo.com") -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert {{ service.client_name }}._use_client_cert_effective() is True - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert {{ service.client_name }}._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert {{ service.client_name }}._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert {{ service.client_name }}._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - {{ service.client_name }}._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert {{ service.client_name }}._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert {{ service.client_name }}._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert {{ service.client_name }}._get_client_cert_source(None, False) is None - assert {{ service.client_name }}._get_client_cert_source(mock_provided_cert_source, False) is None - assert {{ service.client_name }}._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert {{ service.client_name }}._get_client_cert_source(None, True) is mock_default_cert_source - assert {{ service.client_name }}._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source -@mock.patch.object({{ service.client_name }}, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template({{ service.client_name }})) -{% if 'grpc' in opts.transport %} -@mock.patch.object({{ service.async_client_name }}, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template({{ service.async_client_name }})) -{% endif %} -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = {{ service.client_name }}._DEFAULT_UNIVERSE - default_endpoint = {{ service.client_name }}._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = {{ service.client_name }}._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - assert {{ service.client_name }}._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert {{ service.client_name }}._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == {{ service.client_name }}.DEFAULT_MTLS_ENDPOINT - assert {{ service.client_name }}._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert {{ service.client_name }}._get_api_endpoint(None, None, default_universe, "always") == {{ service.client_name }}.DEFAULT_MTLS_ENDPOINT - assert {{ service.client_name }}._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == {{ service.client_name }}.DEFAULT_MTLS_ENDPOINT - assert {{ service.client_name }}._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert {{ service.client_name }}._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - with pytest.raises(MutualTLSChannelError) as excinfo: - {{ service.client_name }}._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." {% if service.version %} {% for method in service.methods.values() %}{% with method_name = method.name|snake_case %} @@ -384,17 +226,7 @@ def test_{{ method_name }}_api_version_header(transport_name): {% endfor %} {% endif %}{# service.version #} -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - assert {{ service.client_name }}._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert {{ service.client_name }}._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert {{ service.client_name }}._get_universe_domain(None, None) == {{ service.client_name }}._DEFAULT_UNIVERSE - - with pytest.raises(ValueError) as excinfo: - {{ service.client_name }}._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -434,84 +266,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] -{% if api.all_method_settings.values()|map(attribute="auto_populated_fields", default=[])|select|list %} -def test__setup_request_id(): - class MockRequest: - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - def __contains__(self, key): - return hasattr(self, key) - - class MockProtoRequest: - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - def HasField(self, key): - return hasattr(self, key) - - # Test with proto3 optional field not in request - request = MockRequest() - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request.request_id) - - # Test with proto3 optional field already in request - request = MockRequest(request_id="already_set") - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert request.request_id == "already_set" - - # Test with non-proto3 optional field empty - request = MockRequest(request_id="") - {{ service.client_name }}._setup_request_id(request, "request_id", False) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request.request_id) - - # Test with non-proto3 optional field already set - request = MockRequest(request_id="already_set") - {{ service.client_name }}._setup_request_id(request, "request_id", False) - assert request.request_id == "already_set" - - # Test with proto3 optional field not in request (MockProtoRequest) - request = MockProtoRequest() - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request.request_id) - - # Test with proto3 optional field already in request (MockProtoRequest) - request = MockProtoRequest(request_id="already_set") - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert request.request_id == "already_set" - - # Test with ValueError - class MockValueErrorRequest: - def HasField(self, key): - raise ValueError("Mismatched field") - def __contains__(self, key): - return hasattr(self, key) - - request = MockValueErrorRequest() - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request.request_id) - - # Test with dict and proto3 optional field not in request - request = {} - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request["request_id"]) - - # Test with dict and proto3 optional field already in request - request = {"request_id": "already_set"} - {{ service.client_name }}._setup_request_id(request, "request_id", True) - assert request["request_id"] == "already_set" - - # Test with dict and non-proto3 optional field empty - request = {"request_id": ""} - {{ service.client_name }}._setup_request_id(request, "request_id", False) - assert re.match(r"{{ test_macros.get_uuid4_re() }}", request["request_id"]) - - # Test with dict and non-proto3 optional field already set - request = {"request_id": "already_set"} - {{ service.client_name }}._setup_request_id(request, "request_id", False) - assert request["request_id"] == "already_set" -{% endif %} @pytest.mark.parametrize("client_class,transport_name", [ {% if 'grpc' in opts.transport %} ({{ service.client_name }}, "grpc"), @@ -896,6 +651,7 @@ def test_{{ service.client_name|snake_case }}_get_mtls_endpoint_and_cert_source( for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -943,6 +699,7 @@ def test_{{ service.client_name|snake_case }}_get_mtls_endpoint_and_cert_source( for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/noxfile.py b/packages/gapic-generator/noxfile.py index 6fac5c48853d..b51ff2160b20 100644 --- a/packages/gapic-generator/noxfile.py +++ b/packages/gapic-generator/noxfile.py @@ -73,6 +73,8 @@ def unit(session): "grpcio-status", "proto-plus", ) + if os.path.exists("../google-api-core"): + session.install("../google-api-core") session.install("-e", ".") session.run( "py.test", @@ -89,6 +91,7 @@ def unit(session): path.join("tests", "unit"), ] ), + env={"PYTHONPATH": "."}, ) @@ -154,6 +157,18 @@ def __call__(self, frag): ) self.session.install(tmp_dir, "-e", ".", "-qqq", "-r", constraints_path) + # Uninstall the PyPI version of google-api-core to prevent import path conflicts + self.session.run("pip", "uninstall", "google-api-core", "-y") + # Override google-api-core with the local version from source + if os.path.exists("../google-api-core"): + self.session.install( + "../google-api-core", "--no-deps" + ) + else: + self.session.install( + "google-api-core", "--no-deps" + ) + # Run the fragment's generated unit tests. # Don't bother parallelizing them: we already parallelize # the fragments, and there usually aren't too many tests per fragment. @@ -182,6 +197,8 @@ def fragment(session, use_ads_templates=False): "pytest-asyncio", "grpcio-tools", ) + if os.path.exists("../google-api-core"): + session.install("../google-api-core") session.install("-e", ".") # The specific failure is `Plugin output is unparseable` @@ -246,6 +263,10 @@ def showcase_library( session.log("-" * 70) # Install gapic-generator-python + if os.path.exists("../google-api-core"): + session.install("../google-api-core") + else: + session.install("google-api-core") session.install("-e", ".") # Install grpcio-tools for protoc @@ -382,6 +403,14 @@ def showcase_library( # Install the library without a constraints file. session.install("-e", tmp_dir) + # Uninstall the PyPI version of google-api-core to prevent import path conflicts + session.run("pip", "uninstall", "google-api-core", "-y") + # Override google-api-core with the local version from source + if os.path.exists("../google-api-core"): + session.install("../google-api-core", "--no-deps") + else: + session.install("google-api-core", "--no-deps") + yield tmp_dir diff --git a/packages/gapic-generator/requirements.in b/packages/gapic-generator/requirements.in index 2776bb919bb8..e9592c64ab26 100644 --- a/packages/gapic-generator/requirements.in +++ b/packages/gapic-generator/requirements.in @@ -1,5 +1,5 @@ click -google-api-core +google-api-core[grpc]>=2.25.0,<3.0.0 googleapis-common-protos jinja2 MarkupSafe diff --git a/packages/gapic-generator/requirements.txt b/packages/gapic-generator/requirements.txt index b4e1c89959be..0c3636eff1a6 100644 --- a/packages/gapic-generator/requirements.txt +++ b/packages/gapic-generator/requirements.txt @@ -1,431 +1,397 @@ # -# This file is autogenerated by pip-compile with Python 3.10 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile --allow-unsafe --generate-hashes --output-file=requirements.txt requirements.in +# pip-compile --generate-hashes --output-file=requirements.txt requirements.in # -aiohappyeyeballs==2.6.1 \ - --hash=sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558 \ - --hash=sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8 +--index-url https://pypi.org/simple + +aiohappyeyeballs==2.7.1 \ + --hash=sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d \ + --hash=sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472 # via aiohttp -aiohttp==3.13.5 \ - --hash=sha256:019a67772e034a0e6b9b17c13d0a8fe56ad9fb150fc724b7f3ffd3724288d9e5 \ - --hash=sha256:02222e7e233295f40e011c1b00e3b0bd451f22cf853a0304c3595633ee47da4b \ - --hash=sha256:023ecba036ddd840b0b19bf195bfae970083fd7024ce1ac22e9bba90464620e9 \ - --hash=sha256:02e048037a6501a5ec1f6fc9736135aec6eb8a004ce48838cb951c515f32c80b \ - --hash=sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8 \ - --hash=sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a \ - --hash=sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2 \ - --hash=sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1 \ - --hash=sha256:147b4f501d0292077f29d5268c16bb7c864a1f054d7001c4c1812c0421ea1ed0 \ - --hash=sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037 \ - --hash=sha256:15c933ad7920b7d9a20de151efcd05a6e38302cbf0e10c9b2acb9a42210a2416 \ - --hash=sha256:178c7b5e62b454c2bc790786e6058c3cc968613b4419251b478c153a4aec32b1 \ - --hash=sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9 \ - --hash=sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a \ - --hash=sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36 \ - --hash=sha256:206b7b3ef96e4ce211754f0cd003feb28b7d81f0ad26b8d077a5d5161436067f \ - --hash=sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b \ - --hash=sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174 \ - --hash=sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b \ - --hash=sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8 \ - --hash=sha256:2837fb92951564d6339cedae4a7231692aa9f73cbc4fb2e04263b96844e03b4e \ - --hash=sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6 \ - --hash=sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c \ - --hash=sha256:31cebae8b26f8a615d2b546fee45d5ffb76852ae6450e2a03f42c9102260d6fe \ - --hash=sha256:327cc432fdf1356fb4fbc6fe833ad4e9f6aacb71a8acaa5f1855e4b25910e4a9 \ - --hash=sha256:329f292ed14d38a6c4c435e465f48bebb47479fd676a0411936cc371643225cc \ - --hash=sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800 \ - --hash=sha256:33add2463dde55c4f2d9635c6ab33ce154e5ecf322bd26d09af95c5f81cfa286 \ - --hash=sha256:347542f0ea3f95b2a955ee6656461fa1c776e401ac50ebce055a6c38454a0adf \ - --hash=sha256:39380e12bd1f2fdab4285b6e055ad48efbaed5c836433b142ed4f5b9be71036a \ - --hash=sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc \ - --hash=sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9 \ - --hash=sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665 \ - --hash=sha256:4bb6bf5811620003614076bdc807ef3b5e38244f9d25ca5fe888eaccea2a9832 \ - --hash=sha256:4beac52e9fe46d6abf98b0176a88154b742e878fdf209d2248e99fcdf73cd297 \ - --hash=sha256:4e704c52438f66fdd89588346183d898bb42167cf88f8b7ff1c0f9fc957c348f \ - --hash=sha256:4eac02d9af4813ee289cd63a361576da36dba57f5a1ab36377bc2600db0cbb73 \ - --hash=sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b \ - --hash=sha256:55b3bdd3292283295774ab585160c4004f4f2f203946997f49aac032c84649e9 \ - --hash=sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090 \ - --hash=sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49 \ - --hash=sha256:636bc362f0c5bbc7372bc3ae49737f9e3030dbce469f0f422c8f38079780363d \ - --hash=sha256:676e5651705ad5d8a70aeb8eb6936c436d8ebbd56e63436cb7dd9bb36d2a9a46 \ - --hash=sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83 \ - --hash=sha256:6a7cbeb06d1070f1d14895eeeed4dac5913b22d7b456f2eb969f11f4b3993796 \ - --hash=sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be \ - --hash=sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d \ - --hash=sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf \ - --hash=sha256:6f497a6876aa4b1a102b04996ce4c1170c7040d83faa9387dd921c16e30d5c83 \ - --hash=sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25 \ - --hash=sha256:77dfa48c9f8013271011e51c00f8ada19851f013cde2c48fca1ba5e0caf5bb06 \ - --hash=sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3 \ - --hash=sha256:7ab7229b6f9b5c1ba4910d6c41a9eb11f543eadb3f384df1b4c293f4e73d44d6 \ - --hash=sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb \ - --hash=sha256:7c35b0bf0b48a70b4cb4fc5d7bed9b932532728e124874355de1a0af8ec4bc88 \ - --hash=sha256:7c4b6668b2b2b9027f209ddf647f2a4407784b5d88b8be4efcc72036f365baf9 \ - --hash=sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be \ - --hash=sha256:888e78eb5ca55a615d285c3c09a7a91b42e9dd6fc699b166ebd5dee87c9ccf14 \ - --hash=sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a \ - --hash=sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c \ - --hash=sha256:8bd3ec6376e68a41f9f95f5ed170e2fcf22d4eb27a1f8cb361d0508f6e0557f3 \ - --hash=sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f \ - --hash=sha256:8f14c50708bb156b3a3ca7230b3d820199d56a48e3af76fa21c2d6087190fe3d \ - --hash=sha256:8f546a4dc1e6a5edbb9fd1fd6ad18134550e096a5a43f4ad74acfbd834fc6670 \ - --hash=sha256:912d4b6af530ddb1338a66229dac3a25ff11d4448be3ec3d6340583995f56031 \ - --hash=sha256:9277145d36a01653863899c665243871434694bcc3431922c3b35c978061bdb8 \ - --hash=sha256:95d14ca7abefde230f7639ec136ade282655431fd5db03c343b19dda72dd1643 \ - --hash=sha256:999802d5fa0389f58decd24b537c54aa63c01c3219ce17d1214cbda3c2b22d2d \ - --hash=sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8 \ - --hash=sha256:9b16c653d38eb1a611cc898c41e76859ca27f119d25b53c12875fd0474ae31a8 \ - --hash=sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1 \ - --hash=sha256:9efcc0f11d850cefcafdd9275b9576ad3bfb539bed96807663b32ad99c4d4b88 \ - --hash=sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb \ - --hash=sha256:a5029cc80718bbd545123cd8fe5d15025eccaaaace5d0eeec6bd556ad6163d61 \ - --hash=sha256:a60eaa2d440cd4707696b52e40ed3e2b0f73f65be07fd0ef23b6b539c9c0b0b4 \ - --hash=sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7 \ - --hash=sha256:a84792f8631bf5a94e52d9cc881c0b824ab42717165a5579c760b830d9392ac9 \ - --hash=sha256:a8a4d3427e8de1312ddf309cc482186466c79895b3a139fed3259fc01dfa9a5b \ - --hash=sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500 \ - --hash=sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6 \ - --hash=sha256:ab2899f9fa2f9f741896ebb6fa07c4c883bfa5c7f2ddd8cf2aafa86fa981b2d2 \ - --hash=sha256:af545c2cffdb0967a96b6249e6f5f7b0d92cdfd267f9d5238d5b9ca63e8edb10 \ - --hash=sha256:b18f31b80d5a33661e08c89e202edabf1986e9b49c42b4504371daeaa11b47c1 \ - --hash=sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3 \ - --hash=sha256:b38765950832f7d728297689ad78f5f2cf79ff82487131c4d26fe6ceecdc5f8e \ - --hash=sha256:b6f6cd1560c5fa427e3b6074bb24d2c64e225afbb7165008903bd42e4e33e28a \ - --hash=sha256:bace460460ed20614fa6bc8cb09966c0b8517b8c58ad8046828c6078d25333b5 \ - --hash=sha256:bca9ef7517fd7874a1a08970ae88f497bf5c984610caa0bf40bd7e8450852b95 \ - --hash=sha256:c180f480207a9b2475f2b8d8bd7204e47aec952d084b2a2be58a782ffcf96074 \ - --hash=sha256:c2b2355dc094e5f7d45a7bb262fe7207aa0460b37a0d87027dcf21b5d890e7d5 \ - --hash=sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b \ - --hash=sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772 \ - --hash=sha256:c719f65bebcdf6716f10e9eff80d27567f7892d8988c06de12bbbd39307c6e3a \ - --hash=sha256:c86969d012e51b8e415a8c6ce96f7857d6a87d6207303ab02d5d11ef0cad2274 \ - --hash=sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94 \ - --hash=sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13 \ - --hash=sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac \ - --hash=sha256:cb979826071c0986a5f08333a36104153478ce6018c58cba7f9caddaf63d5d67 \ - --hash=sha256:cd3db5927bf9167d5a6157ddb2f036f6b6b0ad001ac82355d43e97a4bde76d76 \ - --hash=sha256:d147004fede1b12f6013a6dbb2a26a986a671a03c6ea740ddc76500e5f1c399f \ - --hash=sha256:d3a4834f221061624b8887090637db9ad4f61752001eae37d56c52fddade2dc8 \ - --hash=sha256:d9010032a0b9710f58012a1e9c222528763d860ba2ee1422c03473eab47703e7 \ - --hash=sha256:d97f93fdae594d886c5a866636397e2bcab146fd7a132fd6bb9ce182224452f8 \ - --hash=sha256:df23d57718f24badef8656c49743e11a89fd6f5358fa8a7b96e728fda2abf7d3 \ - --hash=sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be \ - --hash=sha256:e5e5f7debc7a57af53fdf5c5009f9391d9f4c12867049d509bf7bb164a6e295b \ - --hash=sha256:e7d2f8616f0ff60bd332022279011776c3ac0faa0f1b463f7bb12326fbc97a1c \ - --hash=sha256:e999f0c88a458c836d5fb521814e92ed2172c649200336a6df514987c1488258 \ - --hash=sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c \ - --hash=sha256:ec707059ee75732b1ba130ed5f9580fe10ff75180c812bc267ded039db5128c6 \ - --hash=sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56 \ - --hash=sha256:ee5e86776273de1795947d17bddd6bb19e0365fd2af4289c0d2c5454b6b1d36b \ - --hash=sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d \ - --hash=sha256:f34ecee82858e41dd217734f0c41a532bd066bcaab636ad830f03a30b2a96f2a \ - --hash=sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162 \ - --hash=sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1 \ - --hash=sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6 \ - --hash=sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5 \ - --hash=sha256:fe6970addfea9e5e081401bcbadf865d2b6da045472f58af08427e108d618540 \ - --hash=sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254 +aiohttp==3.14.1 \ + --hash=sha256:03ab4530fdcb3a543a122ba4b65ac9919da9fe9f78a03d328a6e38ff962f7aa5 \ + --hash=sha256:07eabb979d236335fed927e137a928c9adfb7df3b9ec7aa31726f133a62be983 \ + --hash=sha256:092e4ce3619a7c6dee52a6bdabda973d9b34b66781f840ce93c7e0cec30cf521 \ + --hash=sha256:10ee9c1753a8f706345b22496c79fbddb5be0599e0823f3738b1534058e25340 \ + --hash=sha256:1601cc37baf5750ccacae618ec2daf020769581695550e3b654a911f859c563d \ + --hash=sha256:1ac8531b638959718e18c2207fbfe297819875da46a740b29dfa29beba64355a \ + --hash=sha256:1b9748363260121d2927704f5d4fc498150669ca3ae93625986ee89c8f80dcd4 \ + --hash=sha256:1c1421eb01d4fd608d88cc8290211d177a58532b55ad94076fb349c5bf467f0a \ + --hash=sha256:1c1af67559445498b502030c35c59db59966f47041ca9de5b4e707f86bd10b5f \ + --hash=sha256:1d459b98a932296c6f0e94f87511a0b1b90a8a02c30a50e60a297619cd5a58ee \ + --hash=sha256:20205f7f5ade7aaec9f4b500549bbc071b046453aed72f9c06dcab87896a83e8 \ + --hash=sha256:23119f8fd4f5d16902ed459b63b100bcd269628075162bddac56cc7b5273b3fb \ + --hash=sha256:237651caadc3a59badd39319c54642b5299e9cc98a3a194310e55d5bb9f5e397 \ + --hash=sha256:24ba13339fed9251d9b1a1bec8c7ab84c0d1675d79d33501e11f94f8b9a84e05 \ + --hash=sha256:250d14af67f6b6a1a4a811049b1afa69d61d617fca6bf33149b3ab1a6dbcf7b8 \ + --hash=sha256:269b76ac5394092b95bc4a098f4fc6c191c083c3bd12775d1e30e663132f6a09 \ + --hash=sha256:27fd7c91e51729b4f7e1577865fa6d34c9adccbc39aabe9000285b48af9f0ec2 \ + --hash=sha256:2964cbf553df4d7a57348da44d961d871895fc1ee4e8c322b2a95612c7b17fba \ + --hash=sha256:2a73f487ab8ef5abbb24b7aa9b73e98eaba9e9e031804ff2416f02eca315ccaf \ + --hash=sha256:2aa92c87868cd13674989f9ee83e5f9f7ea4237589b728048e1f0c8f6caa3271 \ + --hash=sha256:2b7edd08e0a5deb1e8564a2fcd8f4561014a3f05252334671bbf55ddd47db0e5 \ + --hash=sha256:2c840c90759922cb5e6dda94596e079a30fb5a5ba548e7e0dc00574703940847 \ + --hash=sha256:2f73e01dc37122325caf079982621262f96d74823c179038a82fddfc50359264 \ + --hash=sha256:2fbc3ed048b3475b9f0cbcb9978e9d2d3511acd91ead203af26ed9f0056004cf \ + --hash=sha256:2fe3607e71acc6ebb0ec8e492a247bf7a291226192dc0084236dfc12478916f6 \ + --hash=sha256:30099eda75a53c32efb0920e9c33c195314d2cc1c680fbfd30894932ac5f27df \ + --hash=sha256:307f2cff90a764d329e77040603fa032db89c5c24fdad50c4c15334cba744035 \ + --hash=sha256:313701e488100074ce99850404ee36e741abf6330179fec908a1944ecf570126 \ + --hash=sha256:317acd9f8602858dc7d59679812c376c7f0b97bcbbf16e0d6237f54141d8a8a6 \ + --hash=sha256:335c0cc3e3545ce98dcb9cfcb836f40c3411f43fa03dab757597d80c89af8a35 \ + --hash=sha256:34b257ec41345c1e8f2df68fa908a7952f5de932723871eb633ecbbff396c9a4 \ + --hash=sha256:367a9314fdc79dab0fac96e216cb41dd73c85bdca85306ce8999118ba7e0f333 \ + --hash=sha256:38e1e7daaea81df51c952e18483f323d878499a1e2bfe564790e0f9701d6f203 \ + --hash=sha256:3e6fc1a85fa7194a1a7d19f44e8609180f4a8eb5fa4c7ed8b4355f080fad235c \ + --hash=sha256:4132e72c608fe9fecb8f409113567605915b83e9bdd3ea56538d2f9cd35002f1 \ + --hash=sha256:4691802dda97be727f79d86818acaad7eb8e9252626a1d6b519fedbb92d5e251 \ + --hash=sha256:47ddf841cdecc810749921d25606dee45857d12d2ad5ddb7b5bd7eab12e4b365 \ + --hash=sha256:486f7d16ed54c39c2cbd7ca71fd8ba2b8bb7860df65bd7b6ed640bab96a38a8b \ + --hash=sha256:4cd96b5ba05d67ed0cf00b5b405c8cd99586d8e3481e8ee0a831057591af7621 \ + --hash=sha256:4d6e0ac9da31c9c04c84e1c0182ad8d6df35965a85cae29cd71d089621b3ae94 \ + --hash=sha256:4dfd6e47d3c44c2279907607f73a4240b88c69eb8b90da7e2441a8045dfd21da \ + --hash=sha256:4f7215cb3933784f79ed20e5f050e15984f390424339b22375d5a53c933a0491 \ + --hash=sha256:4fe1f1087cbadb280b5e1bb054a4f00d1423c74d6626c5e48400d871d34ecefe \ + --hash=sha256:52cdac9432d8b4a719f35094a818d95adcae0f0b4fe9b9b921909e0c87de9e7d \ + --hash=sha256:5663ee9257cfa1add7253a7da3035a02f31b6600ec48261585e1800a81533080 \ + --hash=sha256:57fc6745a4b7d0f5a9eb4f40a69718be6c0bc1b8368cc9fe89e90118719f4f42 \ + --hash=sha256:5a837f49d901f9e368651b676912bff1104ed8c1a83b280bcd7b29adccef5c9c \ + --hash=sha256:5c0b3e614340c889d575451696374c9d17affd54cd607ca0babed8f8c37b9397 \ + --hash=sha256:5e78b522b7a6e27e0b25d19b247b75039ac4c94f99823e3c9e53ae1603a9f7e9 \ + --hash=sha256:5f2504bc0322437c9a1ff6d3333ca56c7477b727c995f036b976ae17b98372c8 \ + --hash=sha256:603a2c834142172ffddc054067f5ec0ca65d57a0aa98a71bc81952573208e345 \ + --hash=sha256:62a759436b29e677181a9e76bab8b8f689a29cb9c535f45f7c48c9c830d3f8c3 \ + --hash=sha256:634e385930fb6d2d479cf3aa66515955863b77a5e3c2b5894ca259a25b308602 \ + --hash=sha256:64c567bf9eaf664280116a8688f63016e6b32db2505908e2bdaca1b6438142f2 \ + --hash=sha256:672ac254412a24d0d0cf00a9e6c238877e4be5e5fa2d188832c1244f45f31966 \ + --hash=sha256:672b9d65f42eb877f5c3f234a4547e4e1a226ca8c2eed879bb34670a0ce51192 \ + --hash=sha256:686b6c0d3911ec387b444ddf5dc62fb7f7c0a7d5186a7861626496a5ab4aff95 \ + --hash=sha256:6f71173be42d3241d428f760122febb748de0623f44308a6f120d0dd9ec572e3 \ + --hash=sha256:6fd35beba67c4183b09375c5fff9accb47524191a244a99f95fd4472f5402c2b \ + --hash=sha256:6ffbb2f4ec1ceaff7e07d43922954da26b223d188bf30658e561b98e23089444 \ + --hash=sha256:73f05ea02013e02512c3bf42714f1208c57168c779cc6fe23516e4543089d0a6 \ + --hash=sha256:764457a7be60825fb770a644852ff717bcbb5042f189f2bd16df61a81b3f6573 \ + --hash=sha256:797457503c2d426bee06eef808d07b31ede30b65e054444e7de64cad0061b7af \ + --hash=sha256:7c106c26852ca1c2047c6b80384f17100b4e439af276f21ef3d4e2f450ae7e15 \ + --hash=sha256:7fb4bdf95b0561a79f259f9d28fbc109728c5ee7f27aff6391f0ca703a329abe \ + --hash=sha256:819c054312f1af92947e6a55883d1b66feefab11531a7fc45e0fb9b63880b5c2 \ + --hash=sha256:8560b4d712474335d08907db7973f71912d3a9a8f1dee992ec06b5d2fe359496 \ + --hash=sha256:86a6dab78b0e43e2897a3bbe15745aa60dc5423ca437b7b0b164c069bf91b876 \ + --hash=sha256:87a5eea1b2a5e21e1ebdbb33ad4165359189327e63fc4e4894693e7f821ac817 \ + --hash=sha256:896e12dfdbbab9d8f7e16d2b28c6769a60126fa92095d1ebf9473d02593a2448 \ + --hash=sha256:8f6bb621e5863cfe8fe5ff5468002d200ec31f30f1280b259dc505b02595099e \ + --hash=sha256:90d53f1609c29ccc2193945ef732428382a28f78d0456ae4d3daf0d48b74f0f6 \ + --hash=sha256:915fbb7b41b115192259f8c9ae58f3ddc444d2b5579917270211858e606a4afd \ + --hash=sha256:93b032b5ec3255473c143627d21a69ac74ae12f7f33974cb587c564d11b1066f \ + --hash=sha256:94da27378da0610e341c4d30de29a191672683cc82b8f9556e8f7c7212a020fe \ + --hash=sha256:979ed4717f59b8bb12e3963378fa285d93d367e15bcd66c721311826d3c44a6c \ + --hash=sha256:97e704dcd26271f5bda3fa07c3ce0fb76d6d3f8659f4baa1a24442cc9ba177ca \ + --hash=sha256:99abd37084b82f5830c635fddd0b4993b9742a66eb746dacf433c8590e8f9e3c \ + --hash=sha256:9af6779bfb46abf124068327abcdf9ce95c9ef8287a3e8da76ccf2d0f16c28fa \ + --hash=sha256:9e8f2d660c350b3d0e259c7a7e3d9b7fc8b41210cbcc3d4a7076ff0a5e5c2fdc \ + --hash=sha256:a24f677ebe83749039e7bdf862ff0bbb16818ae4193d4ef96505e269375bcce0 \ + --hash=sha256:a9875b46d910cff3ea2f5962f9d266b465459fe634e22556ab9bd6fc1192eea0 \ + --hash=sha256:aa00140699487bd435fde4342d85c94cb256b7cd3a5b9c3396c67f19922afda2 \ + --hash=sha256:ae6be797afdef264e8a84864a85b196ca06045586481b3df8a967322fd2fa844 \ + --hash=sha256:af8b4b81a960eeaf1234971ac3cd0ba5901f3cd42eae42a46b4d089a8b492719 \ + --hash=sha256:b165790117eea512d7f3fb22f1f6dad3d55a7189571993eb015591c1401276d1 \ + --hash=sha256:b238af795833d5731d049d82bc84b768ae6f8f97f0495963b3ed9935c5901cc3 \ + --hash=sha256:b3a03285a7f9c7b016324574a6d92a1c895da6b978cb8f1deee3ac72bc6da178 \ + --hash=sha256:b6feea921016eb3d4e04d65fc4e9ca402d1a3801f562aef94989f54694917af3 \ + --hash=sha256:b6ff7fcee63287ae57b5df3e4f5957ce032122802509246dec1a5bcc55904c95 \ + --hash=sha256:b821a1f7dedf7e37450654e620038ac3b2e81e8fa6ea269337e97101978ec730 \ + --hash=sha256:bb2c0c80d431c0d03f2c7dbf125150fedd4f0de17366a7ca33f7ccb822391842 \ + --hash=sha256:bb33777ea21e8b7ecde0e6fc84f598be0a1192eab1a63bc746d75aa75d38e7bd \ + --hash=sha256:bcfb80a2cc36fba2534e5e5b5264dc7ae6fcd9bf15256da3e53d2f499e6fa29d \ + --hash=sha256:bd869c427324e5cb15195793de951295710db28be7d818247f3097b4ab5d4b96 \ + --hash=sha256:bedb0cd073cc2dc035e30aeb99444389d3cd2113afe4ef9fcd23d439f5bade85 \ + --hash=sha256:c389c482a7e9b9dc3ee2701ac46c4125297a3818875b9c305ddb603c04828fd1 \ + --hash=sha256:c6fa4dc7ad6f8109c70bb1499e589f76b0b792baf39f9b017eb92c8a81d0a199 \ + --hash=sha256:c83afe0ba876be7e943d2e0ba645809ad441575d2840c895c21ee5de93b9377a \ + --hash=sha256:cb21957bb8aca671c1765e32f58164cf0c50e6bf41c0bbbd16da20732ecaf588 \ + --hash=sha256:cf4491381b1b57425c315a56a439251b1bdac07b2275f19a8c44bc57744532ec \ + --hash=sha256:d03f281ed22579314ba00821ce20115a7c0ac430660b4cc05704a3f818b3e004 \ + --hash=sha256:d35143e27778b4bb0fb189562d7f275bff79c62ab8e98459717c0ea617ff2480 \ + --hash=sha256:d3b1a184a9a8f548a6b73f1e26b96b052193e4b3175ed7342aaf1151a1f00a04 \ + --hash=sha256:d44ec478e713ee7f29b439f7eb8dc2b9d4079e11ae114d2c2ac3d5daf30516c8 \ + --hash=sha256:d9d4e294455b23a68c9b8f042d0e8e377a265bcb15332753695f6e5b6819e0ce \ + --hash=sha256:de538791a80e5d862addbc183f70f0158ac9b9bb872bb147f1fd2a683691e087 \ + --hash=sha256:e4e5e0ae56914ecdbf446493addefc0159053dd53962cef37d7839f37f73d505 \ + --hash=sha256:e509a55f681e6158c20f70f102f9cf61fb20fbc382272bc6d94b7343f2582780 \ + --hash=sha256:ec8dc383ee57ea3e883477dcca3f11b65d58199f1080acaf4cd6ad9a99698be4 \ + --hash=sha256:ed09c7eb1c391271c2ed0314a51903e72a3acb653d5ccfc264cdf3ef11f8269d \ + --hash=sha256:eeea07c4397bbc57719c4eed8f9c284874d4f175f9b6d57f7a1546b976d455ca \ + --hash=sha256:eefd9cc9b6d4a2db5f00a26bc3e4f9acf71926a6ec557cd56c9c6f27c290b665 \ + --hash=sha256:f234b4deb12f3ad59127e037bc57c40c21e45b45282df7d3a55a0f409f595296 \ + --hash=sha256:f380468b09d2a81633ee863b0ec5648d364bd17bb8ecfb8c2f387f7ac1faf42c \ + --hash=sha256:f5e6ff2bdbb8f4cd3fbe41f99e25bbcd58e3bf9f13d3dd31a11e7917251cc77a \ + --hash=sha256:f7a16ef45b081454ef844502d87a848876c490c4cb5c650c230f6ec79ed2c1e7 \ + --hash=sha256:faccab372e66bc76d5731525e7f1143c922271725b9d38c9f97edcc66266b451 \ + --hash=sha256:fc0cacab7ba4e56f0f81c82a98c09bed2f39c940107b03a34b168bdf7597edd3 # via -r requirements.in aiosignal==1.4.0 \ --hash=sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e \ --hash=sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7 # via aiohttp -async-timeout==5.0.1 \ - --hash=sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c \ - --hash=sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3 - # via aiohttp attrs==26.1.0 \ --hash=sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309 \ --hash=sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32 # via aiohttp -backports-asyncio-runner==1.2.0 \ - --hash=sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5 \ - --hash=sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162 - # via pytest-asyncio -certifi==2026.4.22 \ - --hash=sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a \ - --hash=sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580 +certifi==2026.6.17 \ + --hash=sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432 \ + --hash=sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db # via requests -cffi==2.0.0 \ - --hash=sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb \ - --hash=sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b \ - --hash=sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f \ - --hash=sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9 \ - --hash=sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44 \ - --hash=sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2 \ - --hash=sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c \ - --hash=sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75 \ - --hash=sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65 \ - --hash=sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e \ - --hash=sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a \ - --hash=sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e \ - --hash=sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25 \ - --hash=sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a \ - --hash=sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe \ - --hash=sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b \ - --hash=sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91 \ - --hash=sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592 \ - --hash=sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187 \ - --hash=sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c \ - --hash=sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1 \ - --hash=sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94 \ - --hash=sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba \ - --hash=sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb \ - --hash=sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165 \ - --hash=sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529 \ - --hash=sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca \ - --hash=sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c \ - --hash=sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6 \ - --hash=sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c \ - --hash=sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0 \ - --hash=sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743 \ - --hash=sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63 \ - --hash=sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5 \ - --hash=sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5 \ - --hash=sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4 \ - --hash=sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d \ - --hash=sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b \ - --hash=sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93 \ - --hash=sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205 \ - --hash=sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27 \ - --hash=sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512 \ - --hash=sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d \ - --hash=sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c \ - --hash=sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037 \ - --hash=sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26 \ - --hash=sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322 \ - --hash=sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb \ - --hash=sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c \ - --hash=sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8 \ - --hash=sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4 \ - --hash=sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414 \ - --hash=sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9 \ - --hash=sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664 \ - --hash=sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9 \ - --hash=sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775 \ - --hash=sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739 \ - --hash=sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc \ - --hash=sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062 \ - --hash=sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe \ - --hash=sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9 \ - --hash=sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92 \ - --hash=sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5 \ - --hash=sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13 \ - --hash=sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d \ - --hash=sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26 \ - --hash=sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f \ - --hash=sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495 \ - --hash=sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b \ - --hash=sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6 \ - --hash=sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c \ - --hash=sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef \ - --hash=sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5 \ - --hash=sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18 \ - --hash=sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad \ - --hash=sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3 \ - --hash=sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7 \ - --hash=sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5 \ - --hash=sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534 \ - --hash=sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49 \ - --hash=sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2 \ - --hash=sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5 \ - --hash=sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453 \ - --hash=sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf +cffi==2.1.0 \ + --hash=sha256:02cb7ff33ded4f1532476731f89ede53e2e488a8e6205515a82144246ffa7dcc \ + --hash=sha256:03e9810d18c646077e501f661b682fbf5dee4676048527ca3cffe66faa9960dd \ + --hash=sha256:0520e1f4c35f44e209cbbb421b67eec42e6a157f59444dfb6058874ff3610e5d \ + --hash=sha256:0582a58f3051372229ca8e7f5f589f9e5632678208d8636fea3676711fdf7fe5 \ + --hash=sha256:0611e7ebf90573a535ebdc33ae9da222d037853983e13359f580fab781ca017f \ + --hash=sha256:0a42c688d19fca6e095a53c6a6e2295a5b050a8b289f109adab02a9e61a25de6 \ + --hash=sha256:0a96b74cda968eebbad56d973efe5098974f0a9fb323865bf99ea1fd24e3e64c \ + --hash=sha256:10537b1df4967ca26d21e5072d7d54188354483b91dc75058968d3f0cf13fbda \ + --hash=sha256:11b3fb55f4f8ad92274ed26705f65d8f91457de71f5380061eb6d125a768fecd \ + --hash=sha256:15faec4adfff450819f3aee0e2e02c812de6edb88203aa58807955db2003472a \ + --hash=sha256:164bff1657b2a74f0b6d54e11c9b375bc97b931f2ca9c43fcf875838da1570dd \ + --hash=sha256:1854b724d00f6654c742097d5387569021be12d3a0f770eae1df8f8acfcc6acd \ + --hash=sha256:19c54ac121cad98450b4896fa9a43ee0180d57bc4bc911a33db6cab1efab6cd3 \ + --hash=sha256:1b96bfe2c4bd825681b7d311ad6d9b7280a091f43e8f63da5729638083cd3bfb \ + --hash=sha256:1e9f50d192a3e525b15a75ab5114e442d83d657b7ec29182a991bc9a88fd3a66 \ + --hash=sha256:1ff3456eab0d889592d1936d6125bbfbc7ae4d3354a700f8bd80450a66445d4d \ + --hash=sha256:2282cd5e38aa8accd03e99d1256af8411c84cdbee6a89d841b563fdbd1f3e50f \ + --hash=sha256:276f20fffd7b396e12516ba8edf9509210ac248cbbc5acbc39cd512f9f59ebe6 \ + --hash=sha256:2b71d409cccee78310ab5dec549aed052aaea483346e282c7b02362596e01bb0 \ + --hash=sha256:2e9dabb9abcb7ad15938c7196ad5c1718a4e6d33cc79b4c0209bdb64c4a54a5c \ + --hash=sha256:30b65779d598c370374fefabf138d456fd6f3216bfa7bedfab1ba82025b0cd93 \ + --hash=sha256:33eb1ad83ebe8f313e0df035c406227d55a79456704a863fad9842136af5ad7d \ + --hash=sha256:35aaea0c7ee0e58a5cd8c2fd1a48fdf7ece0d2699b7ecdda08194e9ce5dd9b3d \ + --hash=sha256:3681e031db29958a7502f5c0c9d6bbc4c36cb20f7b104086fa642d1799631ff8 \ + --hash=sha256:379de10ce1ba048b1448599d1b37b24caee16309d1ac98d3982fc997f768700b \ + --hash=sha256:37f525a7e7e50c017fdebe58b787be310ad59357ae43a053943a6e1a6c526001 \ + --hash=sha256:3b926723c13eba9f81d2ef3820d63aeceec3b2d4639906047bf675cb8a7a500d \ + --hash=sha256:3d7f118b5adbfdfead90c25822690b02bc8074fba949bb7858bec4ebd55adb43 \ + --hash=sha256:46b1c8db8f6122420f32d02fffb924c2fe9bc772d228c7c711748fff56aabb2b \ + --hash=sha256:47ff3a8bfd8cb9da1af7524b965127095055654c177fcfc7578debcb015eecd0 \ + --hash=sha256:4d433a51f1870e43a13b6732f92aaf540ff77c2015097c78556f75a2d6c030e0 \ + --hash=sha256:4f26194e3d95e06501b942642855aed4f953d55e95d7d01b7c4483db3ecff458 \ + --hash=sha256:510aeeeac94811b138077451da1fb18b308a5feab47dd2b603af55804155e1c8 \ + --hash=sha256:5972433ad71a9e46516584ef60a0fda12d9dc459938d1539c3ddecf9bdc1368d \ + --hash=sha256:5ecbd0499275d57506d397eebe1981cee87b47fcd9ef5c22cab7ed7644a39a94 \ + --hash=sha256:6274dcb2d15cef48daa73ed1be5a40d501d74dccd0cd6db364776d12cb6ba022 \ + --hash=sha256:63960549e4f8dc41e31accb97b975abaecfc44c03e396c093a6436763c2ea7db \ + --hash=sha256:64c753a0f87a256020004f37a1c8c02c480e725f910f0b2a0f3f07debd1b2479 \ + --hash=sha256:6af371f3767faeffc6ac1ef57cdfd25844403e9d3f476c5537caee499de96376 \ + --hash=sha256:6ca4919c6e4f89aa99c42510b42cf54596892c00b3f9077f6bdd1505e24b9c8d \ + --hash=sha256:6d194185eabd279f1c05ebe3504265ddfc5ad2b58d0714f7db9f01da592e9eb6 \ + --hash=sha256:702c436735fbe99d59ada02a1f65cfc0d31c0ee8b7290912f8fbc5cd1e4b16c3 \ + --hash=sha256:716ff8ec22f20b4d988b12884086bcef0fc99737043e503f7a3935a6be99b1ea \ + --hash=sha256:762f99479dcb369f60ab9017ad4ab97a36a1dd7c1ee5a3b15db0f4b8659120cd \ + --hash=sha256:7762faa47e8ff7eb80bd261d9a7d8eea2d8baa69de5e95b70c1f338bbe712f02 \ + --hash=sha256:78474632761faa0fb96f30b1c928c84ebcf68713cbb80d15bab09dfe61640fde \ + --hash=sha256:799416bae98336e400981ff6e532d67d5c709cfb30afb79865a1315f94b0e224 \ + --hash=sha256:7d034dcffa09e9a46c93fa3a3be402096cb5354ac6e41ab8e5cc9cd8b642ad76 \ + --hash=sha256:7d28dff1db6764108bc30788d85d61c876beff416d9a49cb9dd7c5a9f34f5804 \ + --hash=sha256:7d3538f9c0e50670f4deb93dbb696576e60590369cae2faf7de681e597a8a1f1 \ + --hash=sha256:7d5980a3433d4b71a5e120f9dd551403d7824e31e2e67124fe2769c404c06913 \ + --hash=sha256:7ea6b3e2c4250ff1de21c630fe72d0f63eb95c2c32ffbf64a358cf4a8836d714 \ + --hash=sha256:86cf8755a791f72c85dc287128cc62d4f24d392e3f1e15837245623f4a33cccc \ + --hash=sha256:88023dfe18799507b73f1dbb0d14326a17465de1bc9c9c7655c22845e9ddc3a2 \ + --hash=sha256:89095c1968b4ba8285840e131bf2891b09ae137fe2146905acae0354fbce1b5e \ + --hash=sha256:8d35c139744adb3e727cd51b1a18324bbe44b8bd41bf8322bca4d41289f48eda \ + --hash=sha256:8e74a6135550c4748af665b1b1118b6aab33b1fc6a16f9aff630af107c3b4512 \ + --hash=sha256:8f9ec95b8a043d3dfbc74d9abc6f7baf524dd27a8dc160b0a32ff9cdab650c28 \ + --hash=sha256:90bec57cf82089383bd06a605b3eb8daebf7e5a668520beaf6e327a83a947699 \ + --hash=sha256:95f2954c2c9473d892eca6e0409f3568b37ab62a8eedb122461f73cc273476e3 \ + --hash=sha256:961be50688f7fba2fa65f63712d3b9b341a22311f5253460ce933f52f0de1c8c \ + --hash=sha256:98fff996e983a36d3aa2eca83af40c5821202e7e6f32d13ae94e3d2286f10cfe \ + --hash=sha256:9b8f0f26ca4e7513c534d351eca551947d053fac438f2a04ac96d882909b0d3a \ + --hash=sha256:9d72af0cf10a76a600a9690078fe31c63b9588c8e86bf9fd353f713c84b5db0f \ + --hash=sha256:9d8272c0e483b024e1b9ad029821470ed8ec65631dbd90217469da0e7cd89f1c \ + --hash=sha256:a016194dbe13d14ee9556e734b772d8d67b947092b268d757fd4290e3ba2dfc2 \ + --hash=sha256:a5781494d4d400a3f47f8f1da94b324f6e6b440a53387774002890a2a2f4b50f \ + --hash=sha256:a95b05f9baf29b91171b3a8bd2020b028835243e7b0ff6bb23e2a3c228518b1b \ + --hash=sha256:aa7a1b53a2a4452ada2d1b5dade9960b2522f1e61293a811a077439e39029565 \ + --hash=sha256:ac0f1a2d0cfa7eea3f2aaf006ab6e70e8feeb16b75d65b7e5939982ca2f11056 \ + --hash=sha256:af5e2915d41fe6c961694d7bfdc8562942638200f3ce2765dfb8b745cf997629 \ + --hash=sha256:b6422532152adf4e59b110cb2808cee7a033800952f5c036b4af047ee43199e7 \ + --hash=sha256:b65f590ef2a44640f9a05dbb548a429b4ade77913ce683ac8b1480777658a6c0 \ + --hash=sha256:ba00f661f8ba35d075c937174e27c2c421cec3942fd2e0ea3e66996757c0fdd9 \ + --hash=sha256:bccbbb5ee76a61f9d99b5bf3846a51d7fca4b6a732fe46f89295610edaf41853 \ + --hash=sha256:bf01d8c84cbea96b944c73b22182e6c7c432b3475632b8111dbfdc95ddad6e13 \ + --hash=sha256:bf5c6cf48238b0eb4c086978c492ad1cbc22373fc5b2d7353b3a598ce6db887a \ + --hash=sha256:c16914df9fb7f500e440e6875fa23ff5e0b31db01fa9c06af98d59a91f0dc2e4 \ + --hash=sha256:c351efb95e832a853a29361675f33a7ce53de1a109cd73fd47af0712213aa4ce \ + --hash=sha256:c4165821e131d6d4ca444347c2b694e2311bcfa3fe5a861cc72968f28867beac \ + --hash=sha256:c5f5df567f6eb216de69be06ce55c8b714090fae02b18a3b40da8163b8c5fa9c \ + --hash=sha256:c941bb58d5a6e1c3892d86e42927ed6c180302f07e6d395d08c416e594b98b46 \ + --hash=sha256:c97f080ea627e2863524c5af3836e2270b5f5dfff1f104392b959f8df0c5d384 \ + --hash=sha256:cb96698e3c7413d906ce83f8ffd245ec1bd94707541f299d0ce4d6b0193e982b \ + --hash=sha256:cbb7640ce37159548d2147b5b8c241f962143d4c71231431820783f4dc78f210 \ + --hash=sha256:cdf2448aab5f661c9315308ec8b93f4e8a1a67a3c733f8631067a2b67d5913dc \ + --hash=sha256:d2117334c3af3bdcb9a88522b844a2bdb5efdc4f71c6c822df55486ae1c3347a \ + --hash=sha256:d53d10f7da99ae46f7373b9150393e9c5eab9b224909982b43832668de4779f5 \ + --hash=sha256:d9fafc5aa2e2a39aaf7f8cc0c1f044a9b07fca12e558dca53a3cc5c654ad67a7 \ + --hash=sha256:db3eb7d46527159a878ec3460e9d40615bc25ba337d477db681aea6e4f05c5d2 \ + --hash=sha256:dbf7c7a88e2bac086f06d14577332760bdeecc42bdec8ac4077f6260557d9326 \ + --hash=sha256:df2b82571a1b30f58a87bf4e5a9e78d2b1eff6c6ce8fd3aa3757221f93f0863f \ + --hash=sha256:df92f2aba50eb4d96718b68ef76f2e57a57b54f2fa62333496d16c6d585a85ca \ + --hash=sha256:eb4e8997a49aa2c08a3e43c9045d224448b8941d88e7ac163c7d383e560cbf98 \ + --hash=sha256:efc1cdd798b1aaf39b4610bba7aad28c9bea9b910f25c784ccf9ec1fa719d1f9 \ + --hash=sha256:f146d154428a2523f9cc7936c02353c2459b8f6cf07d3cd1ee1c0a611109c5d5 \ + --hash=sha256:f5bce581e6b8c235e566a14768a943b172ada3ed73537bb0c0be1edee312d4e7 \ + --hash=sha256:f9912624a0c0b834b7520d7769b3644453aabc0a7e1c839da7359f050750e9bc \ + --hash=sha256:fb62edb5bb52cca65fab91a63afa7561607120d26090a7e8fda6fb9f064726da \ + --hash=sha256:ff067a8d8d880e7809e4ac88eb009bb848870115317b306666502ccad30b147f # via cryptography -charset-normalizer==3.4.7 \ - --hash=sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc \ - --hash=sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c \ - --hash=sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67 \ - --hash=sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4 \ - --hash=sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0 \ - --hash=sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c \ - --hash=sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5 \ - --hash=sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444 \ - --hash=sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153 \ - --hash=sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9 \ - --hash=sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01 \ - --hash=sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217 \ - --hash=sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b \ - --hash=sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c \ - --hash=sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a \ - --hash=sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83 \ - --hash=sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5 \ - --hash=sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7 \ - --hash=sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb \ - --hash=sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c \ - --hash=sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1 \ - --hash=sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42 \ - --hash=sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab \ - --hash=sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df \ - --hash=sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e \ - --hash=sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207 \ - --hash=sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18 \ - --hash=sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734 \ - --hash=sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38 \ - --hash=sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110 \ - --hash=sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18 \ - --hash=sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44 \ - --hash=sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d \ - --hash=sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48 \ - --hash=sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e \ - --hash=sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5 \ - --hash=sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d \ - --hash=sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53 \ - --hash=sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790 \ - --hash=sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c \ - --hash=sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b \ - --hash=sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116 \ - --hash=sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d \ - --hash=sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10 \ - --hash=sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6 \ - --hash=sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2 \ - --hash=sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776 \ - --hash=sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a \ - --hash=sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265 \ - --hash=sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008 \ - --hash=sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943 \ - --hash=sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374 \ - --hash=sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246 \ - --hash=sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e \ - --hash=sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5 \ - --hash=sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616 \ - --hash=sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15 \ - --hash=sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41 \ - --hash=sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960 \ - --hash=sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752 \ - --hash=sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e \ - --hash=sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72 \ - --hash=sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7 \ - --hash=sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8 \ - --hash=sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b \ - --hash=sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4 \ - --hash=sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545 \ - --hash=sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706 \ - --hash=sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366 \ - --hash=sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb \ - --hash=sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a \ - --hash=sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e \ - --hash=sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00 \ - --hash=sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f \ - --hash=sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a \ - --hash=sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1 \ - --hash=sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66 \ - --hash=sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356 \ - --hash=sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319 \ - --hash=sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4 \ - --hash=sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad \ - --hash=sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d \ - --hash=sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5 \ - --hash=sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7 \ - --hash=sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0 \ - --hash=sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686 \ - --hash=sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34 \ - --hash=sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49 \ - --hash=sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c \ - --hash=sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1 \ - --hash=sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e \ - --hash=sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60 \ - --hash=sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0 \ - --hash=sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274 \ - --hash=sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d \ - --hash=sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0 \ - --hash=sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae \ - --hash=sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f \ - --hash=sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d \ - --hash=sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe \ - --hash=sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3 \ - --hash=sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393 \ - --hash=sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1 \ - --hash=sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af \ - --hash=sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44 \ - --hash=sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00 \ - --hash=sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c \ - --hash=sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3 \ - --hash=sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7 \ - --hash=sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd \ - --hash=sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e \ - --hash=sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b \ - --hash=sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8 \ - --hash=sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259 \ - --hash=sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859 \ - --hash=sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46 \ - --hash=sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30 \ - --hash=sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b \ - --hash=sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46 \ - --hash=sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24 \ - --hash=sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a \ - --hash=sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24 \ - --hash=sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc \ - --hash=sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215 \ - --hash=sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063 \ - --hash=sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832 \ - --hash=sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6 \ - --hash=sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79 \ - --hash=sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464 +charset-normalizer==3.4.9 \ + --hash=sha256:0327fcd59a935777d83410750c50600ee9571af2846f71ce40f25b13da1ef380 \ + --hash=sha256:03d07803992c6c7bbc976327f34b18b6160327fc81cb82c9d504720ac0be3b62 \ + --hash=sha256:04ce310cb89c15df659582aee80a0603788732a5e017d5bd5c81158106ce249c \ + --hash=sha256:0d861473f743244d349b50f850d10eb87aeb22bbdcc8e64f79273c94af5a8226 \ + --hash=sha256:0e94703ec9684807f20cfb5eed95c70f67f2a8f21ad620146d7b5a13677b93e5 \ + --hash=sha256:0fa1aec2d32bcc03c8fa0f6f1712caad1adc38509f31142112e5c9daf5b9c833 \ + --hash=sha256:16b65ea0f2465b6fb52aa22de5eca612aa964ddfec00a912e26f4656cbef890b \ + --hash=sha256:16d10d789dd9bcca1173c95af82c58433122564b7bc39385124be735a35cbe99 \ + --hash=sha256:19ac87f93086ce37b86e098888555c4b4bc48102279bae3350098c0ed664b501 \ + --hash=sha256:1d22856ffbe153a602df38e4a5464f0b748a54002e0d69ac6d2ad0a197cc99ec \ + --hash=sha256:21e764fd1e70b6a3e205a0e46f3051701f98a8cb3fad66eeb80e48bb502f8698 \ + --hash=sha256:231ddcbb35e2ff8973e1365db41fe0572662893b99a05deb183b68ad4c0c8bd4 \ + --hash=sha256:253a4a220747e8b5faf57ec320c4f5efb0cef05f647420bf267143ec15dba10a \ + --hash=sha256:280081916dc341820640489a66e4696049401ef1cf6dd672f672e70ad915aca3 \ + --hash=sha256:2a441ea71902098ffe78c5abe6c494f44160b4af614ed16c3d9a3b1d17fd8ee2 \ + --hash=sha256:304b13570067b2547562e308af560b3963857b1fa90bd6afd978130130fe2d6a \ + --hash=sha256:32286a2c8d167e897177b673176c1e3e00d4057caf5d2b64eef9a3666b03018e \ + --hash=sha256:33bdcc2a32c0a0e861f60841a512c8acc658c87c2ac59d89e3a46dacf7d866e4 \ + --hash=sha256:375b83ed0aecfce76c16d198fbc21f3b11b337d68662bea0a995046682a11419 \ + --hash=sha256:3c09a49d6cde137258beb3d551994a2927fd35ad5cf96aed573f61bbd67c5f84 \ + --hash=sha256:3d92613ec25e43b05f042302531ec0f00b8445190e43325880cbd6ab7c2581da \ + --hash=sha256:40a126142a56b2dfc0aacbad1de8310cbf60da7656db0e6b16eebd48e3e93519 \ + --hash=sha256:416c229f77e5ea25b3dfd4b582f8d73d7e43c22320302b9ab128a2d3a0b38efe \ + --hash=sha256:432786d3561e69aeeae6c7e8648964ce0ad05736120135601f87ac26b9c83381 \ + --hash=sha256:43b9e366a31fdd1c87d0eb08f579b4a82b723ea54338f040d6b4e518a026ea29 \ + --hash=sha256:440eede837960000d74978f0eba527be106b5b9aee0daf779d395276ed0b0614 \ + --hash=sha256:45b0cc4e3556cd875e09102988d1ab8356c998b596c9fced84547c8138b487a0 \ + --hash=sha256:476743fe6dfe14a2da12e3ac79125dc84a3b2cf8094369a47a1529b0cd8549fe \ + --hash=sha256:4773092f8019072343a7447203308b176e10199920eb02d6195e81bbb3274c29 \ + --hash=sha256:4b3dac63058cc36820b0dd072f89898604e2d39686fe05321729d00d8ac185a0 \ + --hash=sha256:4d1c96a7a18b9690a4d46df09e3e3382406ae3213727cd1019ebade1c4a81917 \ + --hash=sha256:51307f5c71007673a2bf8232ad973483d281e74cb99c8c5a990af1eefa6277d9 \ + --hash=sha256:51447e9aa2684679af07ca5021c3db526e0284347ebf4ffcec1154c3350cfe32 \ + --hash=sha256:58150c9f9b9a552505912d182ccdf26f6396fb6094816ceebcbb20eecabaed94 \ + --hash=sha256:5b10cd92fc5c498b35a8635df6d5a100207f88b63a4dc1de7ef9a548e1e2cd63 \ + --hash=sha256:5e226f6218febc71f6c1fc2fafb91c226f75bdc1d8fb12d66823716e891608fd \ + --hash=sha256:609b3ba8fcc0fb5ab7af00719d0fb6ad0cb518e48e7712d12fd68f1327951198 \ + --hash=sha256:60f44ade2cf573dad7a277e6f8ca9a51a21dda572b13bd7d8539bb3cd5dbedde \ + --hash=sha256:611057cc5d5c0afc743ba8be6bd828c17e0aaa8643f9d0a9b9bb7dea80eb8012 \ + --hash=sha256:6366a16e1a25018694d6a5d784d09b046edc9eac40ea2b54065c3052672516a1 \ + --hash=sha256:65a7ff3f705e57d392f7261b6d0550fe137c3019477431f1c355e0db0a7d3e15 \ + --hash=sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b \ + --hash=sha256:67830fc78e67501f47bb950471b2dcb9b35b140084429318e862895a8e89c993 \ + --hash=sha256:68ce9f4d6b26d5ccbf7fd4459bf75f74a0a146677ebba80597df60cbdb20e6f4 \ + --hash=sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5 \ + --hash=sha256:69b157c5d3292bcd443faca052f3096f637f1e074b98212a933c074ae23dc3b8 \ + --hash=sha256:75286256590a6320cf106a0d28970d3560aad9ee09aa7b34fb40524792436d35 \ + --hash=sha256:78841cccf1af7b40f6f716338d50c0902dbe88d9f800b3c973b7a9a0a693a642 \ + --hash=sha256:78fa18e436a1a0e58dbd7e02fc4473f3f32cceb12df9dfca542d075961c307d2 \ + --hash=sha256:79580094b00d1789d1f93ea55bc43cb2f611910c72235b7657f3482ddcc1b22d \ + --hash=sha256:7b86a2b16095d250c6f58b3d9b2eee6f4147754344f3dab0922f7c9bf7d226c9 \ + --hash=sha256:83aed2c10721ddd90f68140685391b50811a880af20654c59af6b6c66c40513c \ + --hash=sha256:84fd18bcc17526fc2b3c1af7d2b9217d32c9c04448c16ec693b9b4f1985c3d33 \ + --hash=sha256:871ff67ea1aad4dfd91736464934d56b32dac49f9fbe16cddba36198a7b3a0db \ + --hash=sha256:898f0e9068ca27d37f8e83a5b962821df851532e6c4a7d615c1c033f9da6eedf \ + --hash=sha256:8a79d9f4d8001473a30c163556b3c3bfebec837495a412dde78b51672f6134f9 \ + --hash=sha256:8c041122946b7ba21bb32c45b1aa57b1be35527690aeb3c5c234521085632eee \ + --hash=sha256:90c44bc373b7687f6948b693cceaea1348ae0975d7474746559494468e3c1d84 \ + --hash=sha256:9104ed0bd76a429d46f9ec0dbc9b08ad1d2dcdf2b00a5a0daa1c145329b35b44 \ + --hash=sha256:920079c3f7456fa213e0829ed2073aaa727fd39d889ead5b4f35d0de5460d04f \ + --hash=sha256:93d59d504b230e83c7a843251681959a0b6a9cd76f6e146ce1b8a80eb8739af9 \ + --hash=sha256:9b2aff1c7b3884512b9512c3eaadd9bab39fb45042ffaaa1dd08ff2b9f8109d9 \ + --hash=sha256:9b8e0f3107e2200b76f6054de99016eac3ee6762713587b36baaa7e4bd2ae177 \ + --hash=sha256:9bb41182d93ea91f60b4bc8fbf4c820c69ef8a12ab2d917f3f1834f1acad07e8 \ + --hash=sha256:9cdef90ae47919cae358d8ab15797a800ed41da7aba5d72419fb510729e2ed4b \ + --hash=sha256:a1786910334ed46ab1dd73222f2cd1e05c2c3bb39f6dddb4f8b36fc382058a39 \ + --hash=sha256:a4cfde78a9f2880208d16a93b795726a3017d5977e08d1e162a7a31322479c41 \ + --hash=sha256:a4fbdde9dd4a9ce5fd52c2b3a347bb50cc89483ef783f1cb00d408c13f7a96c0 \ + --hash=sha256:aa99adc8f081b475a12843953db36831eaf83ec33eb46a90629ca6a5de45a616 \ + --hash=sha256:ac351b3b8014eead140e77e9717e2992c6bbe30b63bc3422422eb84865412e3d \ + --hash=sha256:ad41ba96094304aa090f5a30cb6e4fb3b3f1c264c523394b4c39bbacc4dc92ba \ + --hash=sha256:b5314963fce9b0b12743891de876e724997864ee22aa496f903f426c7e2fa5b2 \ + --hash=sha256:bcf74c1df76758a395bf0af608c04c82257523f55c9868b334f06270d0f2112b \ + --hash=sha256:bd47ba7fc3ca94896759ea0109775132d3e7ab921fbf54038e1bab2e46c313c9 \ + --hash=sha256:c0323c9daef75ef2e5083624b4585018a0c9d5e3b40f607eed81a311270b934b \ + --hash=sha256:c1225416b463483160e4af85d5fc3a9690ccb53fd4b1865a6437825f5ede3209 \ + --hash=sha256:c1c948747b03be832dceed96ca815cef7360de9aa19d37c730f8e3f6101aca48 \ + --hash=sha256:c25fe15c70c59eb7c5ce8c06a1f3fa1da0ecc5ea1e7a5922c40fd2fa9b0d5046 \ + --hash=sha256:cc1b0fff8ead343dae06305f954eb8468ba0ec1a97881f42489d198e4ce3c632 \ + --hash=sha256:cd6280cf040f233bd7d3407b743b4b4c74f70e8e1c4199cb112a62c941c0772a \ + --hash=sha256:cd6c3d4b783c556fa00bf540854e42f135e2f256abd29669fcd0da0f2dec79c2 \ + --hash=sha256:d4d6fcde76f94f5cb9e43e9e9a61f16dacefd228cbbf6f1a09bd9b219a92f1a1 \ + --hash=sha256:ddf4af30b417d9fe16481e9b81c27ab2a7cde1ff7ba3e85653b02db7d145dc7b \ + --hash=sha256:df115d4d83168fdf2cae48ef1ff6d1cb4c466364e30861b37121de0f3bf1b990 \ + --hash=sha256:df7276909358e5635ae203673ab7e509ddd224225a8d6b0790bf13eb2bde1cc5 \ + --hash=sha256:e4fd89cc178bced6ad29cb3e6dd4aa63fa5017c3524dbd0b25998fb64a87cc8b \ + --hash=sha256:e9701d0049d92c16703a42771b98d560b95248949f23f8cf7b4eddd201814fb9 \ + --hash=sha256:ee2f2a527e3c1a6e6411eb4209642e138b544a2d72fe5d0d76daf77b24063534 \ + --hash=sha256:f7fb7d750cfa0a070d2c24e831fd3481019a60dd317ea2b39acbcebc08b6ed81 \ + --hash=sha256:f840ed6d8ecba8255df8c42b87fadeda98ddfc6eeec05e2dc66e26d46dd6f58a \ + --hash=sha256:f86c6358749bd4fda175388691e3ba8c46e24c5347d0afd20f9b7edfc9faf07d \ + --hash=sha256:fa36ec09ef71d158186bc79e359ff5fdd6e7996fe8ab638f00d6b93139ba4fcf \ + --hash=sha256:fe2c7201c642b7c308f1675355ad7ff7b66acfe3541625efe5a3ad38f29d6115 # via requests -click==8.3.3 \ - --hash=sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2 \ - --hash=sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613 +click==8.4.2 \ + --hash=sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6 \ + --hash=sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76 # via -r requirements.in -cryptography==48.0.0 \ - --hash=sha256:0890f502ddf7d9c6426129c3f49f5c0a39278ed7cd6322c8755ffca6ee675a13 \ - --hash=sha256:0c558d2cdffd8f4bbb30fc7134c74d2ca9a476f830bb053074498fbc86f41ed6 \ - --hash=sha256:16cd65b9330583e4619939b3a3843eec1e6e789744bb01e7c7e2e62e33c239c8 \ - --hash=sha256:18349bbc56f4743c8b12dc32e2bccb2cf83ee8b69a3bba74ef8ae857e26b3d25 \ - --hash=sha256:1e2d54c8be6152856a36f0882ab231e70f8ec7f14e93cf87db8a2ed056bf160c \ - --hash=sha256:22a5cb272895dce158b2cacdfdc3debd299019659f42947dbdac6f32d68fe832 \ - --hash=sha256:27241b1dc9962e056062a8eef1991d02c3a24569c95975bd2322a8a52c6e5e12 \ - --hash=sha256:2b4d59804e8408e2fea7d1fbaf218e5ec984325221db76e6a241a9abd6cdd95c \ - --hash=sha256:2eb992bbd4661238c5a397594c83f5b4dc2bc5b848c365c8f991b6780efcc5c7 \ - --hash=sha256:369a6348999f94bbd53435c894377b20ab95f25a9065c283570e70150d8abc3c \ - --hash=sha256:3cb07a3ed6431663cd321ea8a000a1314c74211f823e4177fefa2255e057d1ec \ - --hash=sha256:40ba1f85eaa6959837b1d51c9767e230e14612eea4ef110ee8854ada22da1bf5 \ - --hash=sha256:4defde8685ae324a9eb9d818717e93b4638ef67070ac9bc15b8ca85f63048355 \ - --hash=sha256:55b7718303bf06a5753dcdccf2f3945cf18ad7bffde41b61226e4db31ab89a9c \ - --hash=sha256:561215ea3879cb1cbbf272867e2efda62476f240fb58c64de6b393ae19246741 \ - --hash=sha256:58d00498e8933e4a194f3076aee1b4a97dfec1a6da444535755822fe5d8b0b86 \ - --hash=sha256:59baa2cb386c4f0b9905bd6eb4c2a79a69a128408fd31d32ca4d7102d4156321 \ - --hash=sha256:5a5ed8fde7a1d09376ca0b40e68cd59c69fe23b1f9768bd5824f54681626032a \ - --hash=sha256:5b012212e08b8dd5edc78ef54da83dd9892fd9105323b3993eff6bea65dc21d7 \ - --hash=sha256:5c3932f4436d1cccb036cb0eaef46e6e2db91035166f1ad6505c3c9d5a635920 \ - --hash=sha256:614d0949f4790582d2cc25553abd09dd723025f0c0e7c67376a1d77196743d6e \ - --hash=sha256:76341972e1eff8b4bea859f09c0d3e64b96ce931b084f9b9b7db8ef364c30eff \ - --hash=sha256:77a2ccbbe917f6710e05ba9adaa25fb5075620bf3ea6fb751997875aff4ae4bd \ - --hash=sha256:7995ef305d7165c3f11ae07f2517e5a4f1d5c18da1376a0a9ed496336b69e5f3 \ - --hash=sha256:7ce4bfae76319a532a2dc68f82cc32f5676ee792a983187dac07183690e5c66f \ - --hash=sha256:7e8eac43dfca5c4cccc6dad9a80504436fca53bb9bc3100a2386d730fbe6b602 \ - --hash=sha256:84cf79f0dc8b36ac5da873481716e87aef31fcfa0444f9e1d8b4b2cece142855 \ - --hash=sha256:8c7378637d7d88016fa6791c159f698b3d3eed28ebf844ac36b9dc04a14dae18 \ - --hash=sha256:8cd666227ef7af430aa5914a9910e0ddd703e75f039cef0825cd0da71b6b711a \ - --hash=sha256:906cbf0670286c6e0044156bc7d4af9cbb0ef6db9f73e52c3ec56ba6bdde5336 \ - --hash=sha256:9071196d81abc88b3516ac8cdfad32e2b66dd4a5393a8e68a961e9161ddc6239 \ - --hash=sha256:9249e3cd978541d665967ac2cb2787fd6a62bddf1e75b3e347a594d7dacf4f74 \ - --hash=sha256:984a20b0f62a26f48a3396c72e4bc34c66e356d356bf370053066b3b6d54634a \ - --hash=sha256:9be5aafa5736574f8f15f262adc81b2a9869e2cfe9014d52a44633905b40d52c \ - --hash=sha256:9c459db21422be75e2809370b829a87eb37f74cd785fc4aa9ea1e5f43b47cda4 \ - --hash=sha256:9ccdac7d40688ecb5a3b4a604b8a88c8002e3442d6c60aead1db2a89a041560c \ - --hash=sha256:a0e692c683f4df67815a2d258b324e66f4738bd7a96a218c826dce4f4bd05d8f \ - --hash=sha256:a5da777e32ffed6f85a7b2b3f7c5cbc88c146bfcd0a1d7baf5fcc6c52ee35dd4 \ - --hash=sha256:a64697c641c7b1b2178e573cbc31c7c6684cd56883a478d75143dbb7118036db \ - --hash=sha256:ad64688338ed4bc1a6618076ba75fd7194a5f1797ac60b47afe926285adb3166 \ - --hash=sha256:bd72e68b06bb1e96913f97dd4901119bc17f39d4586a5adf2d3e47bc2b9d58b5 \ - --hash=sha256:c17dfe85494deaeddc5ce251aebd1d60bbe6afc8b62071bb0b469431a000124f \ - --hash=sha256:c18684a7f0cc9a3cb60328f496b8e3372def7c5d2df39ac267878b05565aaaae \ - --hash=sha256:cc90c0b39b2e3c65ef52c804b72e3c58f8a04ab2a1871272798e5f9572c17d20 \ - --hash=sha256:db63bf618e5dea46c07de12e900fe1cdd2541e6dc9dbae772a70b7d4d4765f6a \ - --hash=sha256:ea8990436d914540a40ab24b6a77c0969695ed52f4a4874c5137ccf7045a7057 \ - --hash=sha256:ecde28a596bead48b0cfd2a1b4416c3d43074c2d785e3a398d7ec1fc4d0f7fbb \ - --hash=sha256:f5333311663ea94f75dd408665686aaf426563556bb5283554a3539177e03b8c \ - --hash=sha256:fdfef35d751d510fcef5252703621574364fec16418c4a1e5e1055248401054b +cryptography==49.0.0 \ + --hash=sha256:026ac7423e6fa66872d3bf889be5974507da3944f866f704fa200eadacd00001 \ + --hash=sha256:07cab27cc7b7e0fd28e5e26bb9eeedde5c135c868b46de4a27845abe94af6122 \ + --hash=sha256:084ef1af862eb07ec46d25f68689f2102a9fc0e05ce7b80f14f5fe51e4eef0f6 \ + --hash=sha256:0b82e28ee398a386f0807bba7884d30f25218855690f45115831bcce5d90822c \ + --hash=sha256:0e959b578856a3924bc0cbb710fc12c387b9412a951389f3ca61704a9e25f325 \ + --hash=sha256:0f21641cf4b30fca7aee061ced0ec7ad7b073518088b7c9969a297c0ae796c69 \ + --hash=sha256:196ecd6a36e4e9aa10270393bb98d8df88fccee0bf1e5128b91ae4eb4375896d \ + --hash=sha256:2400ef9c9e2299a25614eb1dea3db54a69b1349efd043bfac9c67630d136df36 \ + --hash=sha256:28d8b15e6275f12c8a207dc309dfa957903c927d08d0cc937ee3f63f200693cc \ + --hash=sha256:2afe9051da7ae7bd5905da5a949280c7d2bb75682e188f650a9d0f2756b834c6 \ + --hash=sha256:2eda353d8a27bcbcaa4cbed18994a74ab4d19a2ca897db188ea269ab9b71419b \ + --hash=sha256:32703d93296f5c1f4b53349ad3a250c2cae0fdecd3a3dd5d47e616d8d616af27 \ + --hash=sha256:33cd0565932807baddb67b96dbee92f2c374b5c89dee09fd74079aeb8c8dba61 \ + --hash=sha256:35b151772baff2c74cba7fa290ceaff4c3b11c0c881eb93eb5dbc05a7cfbba18 \ + --hash=sha256:36d1709f992593689b45bda411498d62c6e365f2ca00b84657d4dadd24de16db \ + --hash=sha256:42b0684e0e40cf26122427802486f6d93aea593612603a94fbf260c7eb1e9c1b \ + --hash=sha256:4ae387c9cb68ea569ca17e490d66d8142b81c3cc814bf179974b7d146e490bbb \ + --hash=sha256:53ecee2e23f7169b6117e99fc8a944e5e50f79e69758a83b52a00cb98ab2b2d2 \ + --hash=sha256:66ec79c3904820572d7e987abdf304281f141d37ad9a489b8e97066e7b9b6459 \ + --hash=sha256:67e1d20ad9ef3a563c59ef22e7a8a0b8210bd26604369ea4a30a7c66aefe504e \ + --hash=sha256:6f2debedf9ca60cf1d5bd466475638af5130f89965605cd818484d19987d3a21 \ + --hash=sha256:6fc361c34fb6aac015ce19435876635e5c6d21db31998b0920f675f131e043b8 \ + --hash=sha256:73a205dce83953d131a4aa1e0fd917a2fd1c5b1eef251e9d7152efefcbf5caf7 \ + --hash=sha256:7abcee80084cda3f7691f3eb1ce480d8df49cec637b429aa35986c1de71738aa \ + --hash=sha256:8c25ceb16df5b9435f3f6a9829204985b0e0cbee3b48aacd432c7d2c850b44d9 \ + --hash=sha256:966fe0e9c67490071f14c0d2b1cb2dfb3023c5ce39457343931415f08382f2db \ + --hash=sha256:9e82dcc8e56052715fb18b2429e3bca4823b1629136a2084fc45a9a5cecb9b64 \ + --hash=sha256:b20133d204d2bb56ba047642199603876c872026ca53e79c35b83772ab2cc505 \ + --hash=sha256:b39efa323140595abd3ecca8529d321ae50f55f3aa3ba9cc81ea56a6011953d5 \ + --hash=sha256:b47db11c2c3525083296069b98ac5221907455e989ae0c2e3008bde851921615 \ + --hash=sha256:b87e65d263b3e5d3bb92a57e2a6638e2f31110fa7aa890c7b2dbba42248d0a3f \ + --hash=sha256:b970c6da94d5bb18629db453d14f2a1300f6bf59b61e9b82377931ef95504866 \ + --hash=sha256:be9fcb48a55f023493482827d4f459bd263cc20efde64f204b97c123201850c6 \ + --hash=sha256:c2bc30226390d60ea19d9f82b19db005fe0452154a23c1c410c12ea801e43561 \ + --hash=sha256:c83782480a4a9da4d0feb51950131ba32e12e70813848b3343f6e18c28a66838 \ + --hash=sha256:cbc77da8c523d5abd028635ba850a6966fcee2c82e2bf65a41d1d8afe0f98be9 \ + --hash=sha256:ccac2bfebc306b862133e3bb71f3f6ee8bb525240089b2d952e4144b3a6d5da7 \ + --hash=sha256:d0527ce944105f257f605a827d6ebead966c752038b6e8656abb9c5edee6fc68 \ + --hash=sha256:d8ecde755e2e91bf773fc94e8c9d730cd7f2007004cb492263a794ec3899a1c8 \ + --hash=sha256:e3fb64c420688e5319ae25113a354015abbd8dffbfbc41781a1ea66fc7622ac3 \ + --hash=sha256:e5dfc1e64de5677cec922ffa8da89c546d0415bf6efdf081842e5d44c84e1f0e \ + --hash=sha256:ec5e529fb80935c94fe7b729f9972b50e351a0e6b50aa294fd5cabb109fcc29a \ + --hash=sha256:f37d847238971164fdbc68ade6f6574aecc9c0af714190e2083429ff68f4ce9d \ + --hash=sha256:f78ff2c9ed8dc2d036b0f4d640e22522213d047c1b14e61205a7e55c80a494d4 \ + --hash=sha256:f89660a348f4f78a92366240a61404e337586ef7f5909a2fef59ca88ef505493 \ + --hash=sha256:fc1e275c2f1d97b1a6450b8b0ea3ebfa6e087a611c2b26cb2404d48588abab7b # via google-auth -exceptiongroup==1.3.1 \ - --hash=sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219 \ - --hash=sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598 - # via pytest frozenlist==1.8.0 \ --hash=sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686 \ --hash=sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0 \ @@ -560,13 +526,13 @@ frozenlist==1.8.0 \ # via # aiohttp # aiosignal -google-api-core==2.30.3 \ - --hash=sha256:a85761ba72c444dad5d611c2220633480b2b6be2521eca69cca2dbb3ffd6bfe8 \ - --hash=sha256:e601a37f148585319b26db36e219df68c5d07b6382cff2d580e83404e44d641b +google-api-core[grpc]==2.31.0 \ + --hash=sha256:2be84ee0f584c48e6bde1b36766e23348b361fb7e55e56135fc76ce1c397f9c2 \ + --hash=sha256:ef79fb3784c71cbac89cbd03301ba0c8fb8ad2aa95d7f9204dd9628f7adf59ab # via -r requirements.in -google-auth==2.52.0 \ - --hash=sha256:01f30e1a9e3638698d89464f5e603ce29d18e1c0e63ec31ac570aba4e164aaf5 \ - --hash=sha256:aee92803ba0ff93a70a3b8a35c7b4797837751cd6380b63ff38372b98f3ed627 +google-auth==2.56.0 \ + --hash=sha256:6e88c10217e07a92bfd01cac8ee99e32ccfb08414c3102e6c5b8d58f37a0d1e0 \ + --hash=sha256:f90fa030b569a92654b9d690665a073841df33d57487be53db583a9a0867a553 # via google-api-core googleapis-common-protos[grpc]==1.75.0 \ --hash=sha256:53a062ff3c32552fbd62c11fe23768b78e4ddf0494d5e5fd97d3f4689c75fbbd \ @@ -575,78 +541,75 @@ googleapis-common-protos[grpc]==1.75.0 \ # -r requirements.in # google-api-core # grpc-google-iam-v1 + # grpcio-status grpc-google-iam-v1==0.14.4 \ --hash=sha256:392b3796947ed6334e61171d9ab06bf7eb357f554e5fc7556ad7aab6d0e17038 \ --hash=sha256:412facc320fcbd94034b4df3d557662051d4d8adfa86e0ddb4dca70a3f739964 # via -r requirements.in -grpcio==1.80.0 \ - --hash=sha256:00168469238b022500e486c1c33916acf2f2a9b2c022202cf8a1885d2e3073c1 \ - --hash=sha256:02e64bb0bb2da14d947a49e6f120a75e947250aebe65f9629b62bb1f5c14e6e9 \ - --hash=sha256:05d55e1798756282cddd52d56c896b3e7d673e3a8798c2f1cd05ba249a3bb4de \ - --hash=sha256:09e5e478b3d14afd23f12e49e8b44c8684ac3c5f08561c43a5b9691c54d136ab \ - --hash=sha256:0cb517eb1d0d0aaf1d87af7cc5b801d686557c1d88b2619f5e31fab3c2315921 \ - --hash=sha256:1b97cd29a8eda100b559b455331c487a80915b6ea6bd91cf3e89836c4ee8d957 \ - --hash=sha256:256507e2f524092f1473071a05e65a5b10d84b82e3ff24c5b571513cfaa61e2f \ - --hash=sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257 \ - --hash=sha256:2bea16af2750fd0a899bf1abd9022244418b55d1f37da2202249ba4ba673838d \ - --hash=sha256:2dcc70e9f0ba987526e8e8603a610fb4f460e42899e74e7a518bf3c68fe1bf05 \ - --hash=sha256:2ed770b4c06984f3b47eb0517b1c69ad0b84ef3f40128f51448433be904634cd \ - --hash=sha256:31b9ac4ad1aa28ffee5503821fafd09e4da0a261ce1c1281c6c8da0423c83b6e \ - --hash=sha256:33eb763f18f006dc7fee1e69831d38d23f5eccd15b2e0f92a13ee1d9242e5e02 \ - --hash=sha256:367ce30ba67d05e0592470428f0ec1c31714cab9ef19b8f2e37be1f4c7d32fae \ - --hash=sha256:3b01e1f5464c583d2f567b2e46ff0d516ef979978f72091fd81f5ab7fa6e2e7f \ - --hash=sha256:3cb8130ba457d2aa09fa6b7c3ed6b6e4e6a2685fce63cb803d479576c4d80e21 \ - --hash=sha256:3d4147a97c8344d065d01bbf8b6acec2cf86fb0400d40696c8bdad34a64ffc0e \ - --hash=sha256:43168871f170d1e4ed16ae03d10cd21efa29f190e710a624cee7e5ae07da6f4f \ - --hash=sha256:448c884b668b868562b1bda833c5fce6272d26e1926ec46747cda05741d302c1 \ - --hash=sha256:4560cf0e86514595dbbd330cd65b7afad4b5c4b8c4905c041cfffa138d45e6fd \ - --hash=sha256:46c2390b59d67f84e882694d489f5b45707c657832d7934859ceb8c33f467069 \ - --hash=sha256:4e78c4ac0d97dc2e569b2f4bcbbb447491167cb358d1a389fc4af71ab6f70411 \ - --hash=sha256:4ed39fbdcf9b87370f6e8df4e39ca7b38b3e5e9d1b0013c7b6be9639d6578d14 \ - --hash=sha256:50a9871536d71c4fba24ee856abc03a87764570f0c457dd8db0b4018f379fed9 \ - --hash=sha256:51b4a7189b0bef2aa30adce3c78f09c83526cf3dddb24c6a96555e3b97340440 \ - --hash=sha256:52d143637e3872633fc7dd7c3c6a1c84e396b359f3a72e215f8bf69fd82084fc \ - --hash=sha256:5c07e82e822e1161354e32da2662f741a4944ea955f9f580ec8fb409dd6f6060 \ - --hash=sha256:627fb7312171cdc52828bd6fac8d7028ff2a64b89f1957b6f3416caa2218d141 \ - --hash=sha256:68e5851ac4b9afe07e7f84483803ad167852570d65326b34d54ca560bfa53fb6 \ - --hash=sha256:7b641fc3f1dc647bfd80bd713addc68f6d145956f64677e56d9ebafc0bd72388 \ - --hash=sha256:8502122a3cc1714038e39a0b071acb1207ca7844208d5ea0d091317555ee7106 \ - --hash=sha256:873ff5d17d68992ef6605330127425d2fc4e77e612fa3c3e0ed4e668685e3140 \ - --hash=sha256:886457a7768e408cdce226ad1ca67d2958917d306523a0e21e1a2fdaa75c9c9c \ - --hash=sha256:8ac393b58aa16991a2f1144ec578084d544038c12242da3a215966b512904d0f \ - --hash=sha256:8eb613f02d34721f1acf3626dfdb3545bd3c8505b0e52bf8b5710a28d02e8aa7 \ - --hash=sha256:92d787312e613754d4d8b9ca6d3297e69994a7912a32fa38c4c4e01c272974b0 \ - --hash=sha256:93b6f823810720912fd131f561f91f5fed0fda372b6b7028a2681b8194d5d294 \ - --hash=sha256:9a6284a5d907c37db53350645567c522be314bac859a64a7a5ca63b77bb7958f \ - --hash=sha256:9fe648599c0e37594c4809d81a9e77bd138cc82eb8baa71b6a86af65426723ff \ - --hash=sha256:a1dc80fe55685b4a543555e6eef975303b36c8db1023b1599b094b92aa77965f \ - --hash=sha256:a361c20ec1ccd3c3953d20fb6d7b4125093bdd10dff44c5e2bbb39e58917cedc \ - --hash=sha256:a72d84ad0514db063e21887fbacd1fd7acb4d494a564cae22227cd45c7fbf199 \ - --hash=sha256:aacdfb4ed3eb919ca997504d27e03d5dba403c85130b8ed450308590a738f7a4 \ - --hash=sha256:ba0915d51fd4ced2db5ff719f84e270afe0e2d4c45a7bdb1e8d036e4502928c2 \ - --hash=sha256:ba0db34f7e1d803a878284cd70e4c63cb6ae2510ba51937bf8f45ba997cefcf7 \ - --hash=sha256:bac1d573dfa84ce59a5547073e28fa7326d53352adda6912e362da0b917fcef4 \ - --hash=sha256:c51bf8ac4575af2e0678bccfb07e47321fc7acb5049b4482832c5c195e04e13a \ - --hash=sha256:c624cc9f1008361014378c9d776de7182b11fe8b2e5a81bc69f23a295f2a1ad0 \ - --hash=sha256:c71309cfce2f22be26aa4a847357c502db6c621f1a49825ae98aa0907595b193 \ - --hash=sha256:ce1794f4ea6cc3ca29463f42d665c32ba1b964b48958a66497917fe9069f26e6 \ - --hash=sha256:d334591df610ab94714048e0d5b4f3dd5ad1bee74dfec11eee344220077a79de \ - --hash=sha256:d8e11f167935b3eb089ac9038e1a063e6d7dbe995c0bb4a661e614583352e76f \ - --hash=sha256:dc053420fc75749c961e2a4c906398d7c15725d36ccc04ae6d16093167223b58 \ - --hash=sha256:deb10a1528473c11f72a0939eed36d83e847d7cbb63e8cc5611fb7a912d38614 \ - --hash=sha256:dfab85db094068ff42e2a3563f60ab3dddcc9d6488a35abf0132daec13209c8a \ - --hash=sha256:e172cf795a3ba5246d3529e4d34c53db70e888fa582a8ffebd2e6e48bc0cba50 \ - --hash=sha256:e9e408fc016dffd20661f0126c53d8a31c2821b5c13c5d67a0f5ed5de93319ad \ - --hash=sha256:ec0a592e926071b4abad50c1495cd0d0d513324b3ff5e7267067c33ba27506e4 \ - --hash=sha256:f14b618fc30de822681ee986cfdcc2d9327229dc4c98aed16896761cacd468b9 \ - --hash=sha256:f49eddcac43c3bf350c0385366a58f36bed8cc2c0ec35ef7b74b49e56552c0c2 \ - --hash=sha256:f7691a6788ad9196872f95716df5bc643ebba13c97140b7a5ee5c8e75d1dea81 +grpcio==1.82.1 \ + --hash=sha256:011c8badee95734dee8bf05ce3464756a0ac3ebb8d443afd20c0e2b5e4640ad9 \ + --hash=sha256:06127691866e295c14e84a1fb86356dd962254f6abd0da4ca4b001eea9e89438 \ + --hash=sha256:0d8299c285fe6cc6a1f56badf8d3bc5078c8d20273ee64bafa3783b4bc29a769 \ + --hash=sha256:0ddb18a9a9e1f46692b3567ae4abb3f8d117ce6afea48650f8eca06d8ab5d06f \ + --hash=sha256:1e822b2774f719c017cbe700b6e47173b6ae290fb84906f52a5a3c2c60b62e1e \ + --hash=sha256:1eae24810720734598e3e6a1a528d5de0f265fe3fc86575e9ecce424b9ec7379 \ + --hash=sha256:1ecfde669cb687ac020d31ff76debe5dc7a62213335f02262eb6625628da1c03 \ + --hash=sha256:1fa3223a3a2e1db74f4c2b255189eb7ea875dfba56e221d252ee3fc7b204778e \ + --hash=sha256:2ba199205ff46c7778290fe1673c91ac8e7e45678dd5c86e9e56fa33ec8788f6 \ + --hash=sha256:2c0c8270833395644c3fe6b6a806397955a2bc0538000a19a78b90c05a6c16e0 \ + --hash=sha256:35f990f7784c8fd2872644f07f96ebb4d9e48e145a190ab80d0280af91a1bfb2 \ + --hash=sha256:38e9dcb5258226fb3282630b31b16a968df52c8c6ad514af540646e0a4578f8a \ + --hash=sha256:3d21f19838dc255ecbb79321b15ae9b98fbddff4c3d4aedb0a81bdd7f4ab572a \ + --hash=sha256:3dbfb52c36d9511ac2b8e6c94fdde837b393ae520cc321f52a333a2deedf5a90 \ + --hash=sha256:3dde70abfc80b3be11de53ba0d601c439e7fb2afd3583ad1788d1146bec92fdc \ + --hash=sha256:46536a4a1f4434df3c851b9254ff6fc7df5705b273681a15ca277d5921c178a0 \ + --hash=sha256:4c816180e31e273caaec6f8bd86a8392499d5bbb26f41da44e3dce48bde69095 \ + --hash=sha256:50fd2fe83426b1b1c6cdc4d72d555223b7dddf8ce07c5bac218b13fc6d684c6f \ + --hash=sha256:5dafb1ece8ed45dee7c738f166ec82e19673221ed5ab8967f72858a4685345b2 \ + --hash=sha256:5e171d5f0d6a0af78ea7512783f170a44f80c165259d8773e3a354a7f991f2b5 \ + --hash=sha256:5e5c4dc0a59b0f8490a6bdfd6fc8395b9d8ad8a8407c7d67ca7b5bba15c0877f \ + --hash=sha256:60b0f2c95337694fc094b77d9f60f50566c84b5677393e342eb98daeee242d98 \ + --hash=sha256:644ae1b94266ac785330f4590a69e52b6a7eb73029043a02209db81c81397d69 \ + --hash=sha256:707b24abd90fcb1e45bcc080577da1dbf9971d107490589b9539af8e1e77b4b5 \ + --hash=sha256:7d7ede11d747b4e1bd05e3bc0260e155b65a88735a895a10f6521f19b889511e \ + --hash=sha256:91859d1cac5f47caec5fc40e9f827500cdb54ce5b36450dc9a65616b5af49c17 \ + --hash=sha256:9d76152d7c31d7210d4a106e5d8b64da5bba5d6abf11be30e2f7b0a0c59bbcbf \ + --hash=sha256:a6bd5daf5bde7b24d7ad2cbaf8bf9eac620d96222016bb5e7ddde930dec0673f \ + --hash=sha256:b064fc444812bdaa9825d33c26f8d732d63ee6a5d78557c1faf92c98687fed27 \ + --hash=sha256:b454a2d97bfab7565683a02345f86bd182ab69fd7c2bdb7414171e7538f266b1 \ + --hash=sha256:b758540a24d5394a9c578bf9f6126389f474b106ac3d9df1d53de56cb14c9fd9 \ + --hash=sha256:b85f4564926fb23114d239392bdcae200db1e6179629edd7d7ab0ab89c96a197 \ + --hash=sha256:b89cff456796d2f0581783726ad017a2c70aff2d27b0f05504c34e2e417f7560 \ + --hash=sha256:b8e110c66df5204c0506d6c8787b35d48b8b699ef5aa366d6c4d67325c67fe9a \ + --hash=sha256:bd2f45e46fff5b91c10997d0743a987517a7dde67c64c592835c2dcaac66f587 \ + --hash=sha256:c09bd5fa0d5b1fbd773ec349fe61441c3e4ebf168c229aa7538a820bdfad6a58 \ + --hash=sha256:c40d94ba820329cc191981bc22fa6f6eed0799c6d921f3c6709521d59d4a2fd7 \ + --hash=sha256:c4ba4aac238f685743575d9d700003ac16537cce26e7c774993134f530652464 \ + --hash=sha256:c80c9741dcef192f669876a81957cf7713b441c2f0c43631350d75fa49321d31 \ + --hash=sha256:cf855b1af246720f567b0ce5d0724d45dfa4188eecc3296a2a69257b11b9e94b \ + --hash=sha256:d6650a7c1ebb7921c70e12a385439a8118efb99e669fa9ed31cf25db1843937c \ + --hash=sha256:d6e8a08f7038ba7a77f71e250804e4aba84fe91d22cfc54ff43c07b7529c4728 \ + --hash=sha256:ddb30cb13e25bc13cea70ffc69d6d90c49d36ea6c1d4549e6912f70177834cac \ + --hash=sha256:e06503106e7271e0a49fd5a1ac04747f1e47e87d900476db6fe45bc87ee411f4 \ + --hash=sha256:e203d2e19d471630084a16c815616f8211dff21c268ab3c5f5bf38417832e074 \ + --hash=sha256:e20f1edbb15f99e3128ec86433f9785fd5a451d8f115e74fe0056134f092a9d5 \ + --hash=sha256:e31fd780b261830720cb70b0fd8f0aa51d49e75a66d7464ad2e31d4b765f2580 \ + --hash=sha256:ed6fc621d6f366c88a60f0b971d5afd21d441d9aa561ee688de5b7acdb2cf901 \ + --hash=sha256:f5523099c98c292ea1ae08e617249db760c56a78f8deae879027fe7d1ffbcbf6 \ + --hash=sha256:f853eae07235a51a27bb5d6a9a175a59ca55dc9b99edc6ce2f76f07332d333ae \ + --hash=sha256:ff99bc8cafb6a952201c37b995f425e641c93ffa6e072258525feab57290141d # via + # google-api-core # googleapis-common-protos # grpc-google-iam-v1 -idna==3.15 \ - --hash=sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8 \ - --hash=sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc + # grpcio-status +grpcio-status==1.82.1 \ + --hash=sha256:71c7f2bea725c0027fa396b77a55d4e9d90591bab90de4c1c03d4df9a56552f0 \ + --hash=sha256:d9de8ac34763cd468130fdd2923294af7c3d28d09426f6c45221d27c25931130 + # via google-api-core +idna==3.18 \ + --hash=sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2 \ + --hash=sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848 # via # requests # yarl @@ -1105,30 +1068,31 @@ propcache==0.5.2 \ # via # aiohttp # yarl -proto-plus==1.28.0 \ - --hash=sha256:38e5696342835b08fc116f30a25665b29531cda9d5d5643e9b81fc312385abd9 \ - --hash=sha256:a630604310899e73c59ec302e5765c058d412b2f090b9c79c8822589f14955b8 +proto-plus==1.28.1 \ + --hash=sha256:6660f5f1970874bdcfc3088b435188a36a37bd3596668f7d726417c4ae8cfbed \ + --hash=sha256:832e68e7fe064cf90ab153b6e5eb935b27891bb89aaeb68b115e9b702f6cb168 # via # -r requirements.in # google-api-core -protobuf==7.34.1 \ - --hash=sha256:34b84ce27680df7cca9f231043ada0daa55d0c44a2ddfaa58ec1d0d89d8bf60a \ - --hash=sha256:403b093a6e28a960372b44e5eb081775c9b056e816a8029c61231743d63f881a \ - --hash=sha256:5185e0e948d07abe94bb76ec9b8416b604cfe5da6f871d67aad30cbf24c3110b \ - --hash=sha256:8ff40ce8cd688f7265326b38d5a1bed9bfdf5e6723d49961432f83e21d5713e4 \ - --hash=sha256:9ce42245e704cc5027be797c1db1eb93184d44d1cdd71811fb2d9b25ad541280 \ - --hash=sha256:bb3812cd53aefea2b028ef42bd780f5b96407247f20c6ef7c679807e9d188f11 \ - --hash=sha256:d8b2cc79c4d8f62b293ad9b11ec3aebce9af481fa73e64556969f7345ebf9fc7 \ - --hash=sha256:e97b55646e6ce5cbb0954a8c28cd39a5869b59090dfaa7df4598a7fba869468c +protobuf==7.35.1 \ + --hash=sha256:11d6b0ec246892d85215b0a13ca6e0233cf5284b68f0ac02646427f4ff88a799 \ + --hash=sha256:230a75ddfc2de4806e56696ce9640c1cdfdb6543b7cfce98d42a4c0a0e7bdb87 \ + --hash=sha256:24f857477359a85c0c235261b8ba905fd51b2562f4a64ca1df5473f29850cbf6 \ + --hash=sha256:353652e4efd0bca5b5fc2656abf8307ef351f0cf938c9eba09f0e09c20a25c30 \ + --hash=sha256:4bc97768d8fe4ad6743c8a19403e314511ed9f6d13205b687e52421c023ac1b9 \ + --hash=sha256:74758715c53d7158fb76caf4f0cfdacc5329a4b1bb994f865d6cf302d413a1c4 \ + --hash=sha256:b73f9489a4b8b1c9cb1f8ed951c736392592edb24b9d6819f36d2e10b171d5b4 \ + --hash=sha256:ce115a26fe0c39a2c29973d914d327e516a6455464489fe3cd1e51a1b354f81a # via # -r requirements.in # google-api-core # googleapis-common-protos # grpc-google-iam-v1 + # grpcio-status # proto-plus -pyasn1==0.6.3 \ - --hash=sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf \ - --hash=sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde +pyasn1==0.6.4 \ + --hash=sha256:9c447d8431c947fe4c8febc4ed9e760bc29011a5b01e5c74b67025bd9fb8ce81 \ + --hash=sha256:deda9277cfd454080ec40b207fb6df82206a3a2688735233cdcd8d3d565f088b # via pyasn1-modules pyasn1-modules==0.4.2 \ --hash=sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a \ @@ -1146,13 +1110,13 @@ pypandoc==1.17 \ --hash=sha256:01fdbffa61edb9f8e82e8faad6954efcb7b6f8f0634aead4d89e322a00225a67 \ --hash=sha256:51179abfd6e582a25ed03477541b48836b5bba5a4c3b282a547630793934d799 # via -r requirements.in -pytest==9.0.3 \ - --hash=sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9 \ - --hash=sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c +pytest==9.1.1 \ + --hash=sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313 \ + --hash=sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c # via pytest-asyncio -pytest-asyncio==1.3.0 \ - --hash=sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5 \ - --hash=sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5 +pytest-asyncio==1.4.0 \ + --hash=sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1 \ + --hash=sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42 # via -r requirements.in pyyaml==6.0.3 \ --hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \ @@ -1231,200 +1195,125 @@ pyyaml==6.0.3 \ # via # -r requirements.in # libcst -requests==2.33.1 \ - --hash=sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517 \ - --hash=sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a +requests==2.34.2 \ + --hash=sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0 \ + --hash=sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed # via google-api-core -tomli==2.4.1 \ - --hash=sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853 \ - --hash=sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe \ - --hash=sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5 \ - --hash=sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d \ - --hash=sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd \ - --hash=sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26 \ - --hash=sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54 \ - --hash=sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6 \ - --hash=sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c \ - --hash=sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a \ - --hash=sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd \ - --hash=sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f \ - --hash=sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5 \ - --hash=sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9 \ - --hash=sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662 \ - --hash=sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9 \ - --hash=sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1 \ - --hash=sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585 \ - --hash=sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e \ - --hash=sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c \ - --hash=sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41 \ - --hash=sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f \ - --hash=sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085 \ - --hash=sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15 \ - --hash=sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7 \ - --hash=sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c \ - --hash=sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36 \ - --hash=sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076 \ - --hash=sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac \ - --hash=sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8 \ - --hash=sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232 \ - --hash=sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece \ - --hash=sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a \ - --hash=sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897 \ - --hash=sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d \ - --hash=sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4 \ - --hash=sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917 \ - --hash=sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396 \ - --hash=sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a \ - --hash=sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc \ - --hash=sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba \ - --hash=sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f \ - --hash=sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257 \ - --hash=sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30 \ - --hash=sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf \ - --hash=sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9 \ - --hash=sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049 - # via pytest -typing-extensions==4.15.0 \ - --hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \ - --hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548 +typing-extensions==4.16.0 \ + --hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8 \ + --hash=sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5 # via + # aiohttp # aiosignal - # cryptography - # exceptiongroup # grpcio - # multidict # pytest-asyncio urllib3==2.7.0 \ --hash=sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c \ --hash=sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897 # via requests -yarl==1.23.0 \ - --hash=sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc \ - --hash=sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4 \ - --hash=sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85 \ - --hash=sha256:0e1fdaa14ef51366d7757b45bde294e95f6c8c049194e793eedb8387c86d5993 \ - --hash=sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222 \ - --hash=sha256:115136c4a426f9da976187d238e84139ff6b51a20839aa6e3720cd1026d768de \ - --hash=sha256:13a563739ae600a631c36ce096615fe307f131344588b0bc0daec108cdb47b25 \ - --hash=sha256:16c6994ac35c3e74fb0ae93323bf8b9c2a9088d55946109489667c510a7d010e \ - --hash=sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2 \ - --hash=sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e \ - --hash=sha256:1932b6b8bba8d0160a9d1078aae5838a66039e8832d41d2992daa9a3a08f7860 \ - --hash=sha256:1b6b572edd95b4fa8df75de10b04bc81acc87c1c7d16bcdd2035b09d30acc957 \ - --hash=sha256:1c3a3598a832590c5a3ce56ab5576361b5688c12cb1d39429cf5dba30b510760 \ - --hash=sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52 \ - --hash=sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788 \ - --hash=sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912 \ - --hash=sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719 \ - --hash=sha256:2569b67d616eab450d262ca7cb9f9e19d2f718c70a8b88712859359d0ab17035 \ - --hash=sha256:263cd4f47159c09b8b685890af949195b51d1aa82ba451c5847ca9bc6413c220 \ - --hash=sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412 \ - --hash=sha256:2a6940a074fb3c48356ed0158a3ca5699c955ee4185b4d7d619be3c327143e05 \ - --hash=sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41 \ - --hash=sha256:31c9921eb8bd12633b41ad27686bbb0b1a2a9b8452bfdf221e34f311e9942ed4 \ - --hash=sha256:34b6cf500e61c90f305094911f9acc9c86da1a05a7a3f5be9f68817043f486e4 \ - --hash=sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd \ - --hash=sha256:389871e65468400d6283c0308e791a640b5ab5c83bcee02a2f51295f95e09748 \ - --hash=sha256:39004f0ad156da43e86aa71f44e033de68a44e5a31fc53507b36dd253970054a \ - --hash=sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4 \ - --hash=sha256:3ceb13c5c858d01321b5d9bb65e4cf37a92169ea470b70fec6f236b2c9dd7e34 \ - --hash=sha256:411225bae281f114067578891bc75534cfb3d92a3b4dfef7a6ca78ba354e6069 \ - --hash=sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25 \ - --hash=sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2 \ - --hash=sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb \ - --hash=sha256:4966242ec68afc74c122f8459abd597afd7d8a60dc93d695c1334c5fd25f762f \ - --hash=sha256:4a42e651629dafb64fd5b0286a3580613702b5809ad3f24934ea87595804f2c5 \ - --hash=sha256:4a59ba56f340334766f3a4442e0efd0af895fae9e2b204741ef885c446b3a1a8 \ - --hash=sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c \ - --hash=sha256:5023346c4ee7992febc0068e7593de5fa2bf611848c08404b35ebbb76b1b0512 \ - --hash=sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6 \ - --hash=sha256:51430653db848d258336cfa0244427b17d12db63d42603a55f0d4546f50f25b5 \ - --hash=sha256:531ef597132086b6cf96faa7c6c1dcd0361dd5f1694e5cc30375907b9b7d3ea9 \ - --hash=sha256:53ad387048f6f09a8969631e4de3f1bf70c50e93545d64af4f751b2498755072 \ - --hash=sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5 \ - --hash=sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277 \ - --hash=sha256:578110dd426f0d209d1509244e6d4a3f1a3e9077655d98c5f22583d63252a08a \ - --hash=sha256:5ec2f42d41ccbd5df0270d7df31618a8ee267bfa50997f5d720ddba86c4a83a6 \ - --hash=sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae \ - --hash=sha256:5f10fd85e4b75967468af655228fbfd212bdf66db1c0d135065ce288982eda26 \ - --hash=sha256:609d3614d78d74ebe35f54953c5bbd2ac647a7ddb9c30a5d877580f5e86b22f2 \ - --hash=sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4 \ - --hash=sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70 \ - --hash=sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723 \ - --hash=sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c \ - --hash=sha256:6e87a6e8735b44816e7db0b2fbc9686932df473c826b0d9743148432e10bb9b9 \ - --hash=sha256:6f0fd84de0c957b2d280143522c4f91a73aada1923caee763e24a2b3fda9f8a5 \ - --hash=sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e \ - --hash=sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c \ - --hash=sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4 \ - --hash=sha256:75e3026ab649bf48f9a10c0134512638725b521340293f202a69b567518d94e0 \ - --hash=sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2 \ - --hash=sha256:7c6b9461a2a8b47c65eef63bb1c76a4f1c119618ffa99ea79bc5bb1e46c5821b \ - --hash=sha256:803a3c3ce4acc62eaf01eaca1208dcf0783025ef27572c3336502b9c232005e7 \ - --hash=sha256:80e6d33a3d42a7549b409f199857b4fb54e2103fc44fb87605b6663b7a7ff750 \ - --hash=sha256:8419ebd326430d1cbb7efb5292330a2cf39114e82df5cc3d83c9a0d5ebeaf2f2 \ - --hash=sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474 \ - --hash=sha256:85e9beda1f591bc73e77ea1c51965c68e98dafd0fec72cdd745f77d727466716 \ - --hash=sha256:877b0738624280e34c55680d6054a307aa94f7d52fa0e3034a9cc6e790871da7 \ - --hash=sha256:88f9fb0116fbfcefcab70f85cf4b74a2b6ce5d199c41345296f49d974ddb4123 \ - --hash=sha256:8c4fe09e0780c6c3bf2b7d4af02ee2394439d11a523bbcf095cf4747c2932007 \ - --hash=sha256:93a784271881035ab4406a172edb0faecb6e7d00f4b53dc2f55919d6c9688595 \ - --hash=sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe \ - --hash=sha256:95451e6ce06c3e104556d73b559f5da6c34a069b6b62946d3ad66afcd51642ea \ - --hash=sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598 \ - --hash=sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679 \ - --hash=sha256:9cbf44c5cb4a7633d078788e1b56387e3d3cf2b8139a3be38040b22d6c3221c8 \ - --hash=sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83 \ - --hash=sha256:a0e317df055958a0c1e79e5d2aa5a5eaa4a6d05a20d4b0c9c3f48918139c9fc6 \ - --hash=sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f \ - --hash=sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94 \ - --hash=sha256:a3d2bff8f37f8d0f96c7ec554d16945050d54462d6e95414babaa18bfafc7f51 \ - --hash=sha256:a41bcf68efd19073376eb8cf948b8d9be0af26256403e512bb18f3966f1f9120 \ - --hash=sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039 \ - --hash=sha256:a8d00f29b42f534cc8aa3931cfe773b13b23e561e10d2b26f27a8d309b0e82a1 \ - --hash=sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05 \ - --hash=sha256:ab5f043cb8a2d71c981c09c510da013bc79fd661f5c60139f00dd3c3cc4f2ffb \ - --hash=sha256:ac09d42f48f80c9ee1635b2fcaa819496a44502737660d3c0f2ade7526d29144 \ - --hash=sha256:aecfed0b41aa72b7881712c65cf764e39ce2ec352324f5e0837c7048d9e6daaa \ - --hash=sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a \ - --hash=sha256:b35d13d549077713e4414f927cdc388d62e543987c572baee613bf82f11a4b99 \ - --hash=sha256:b39cb32a6582750b6cc77bfb3c49c0f8760dc18dc96ec9fb55fbb0f04e08b928 \ - --hash=sha256:b5405bb8f0e783a988172993cfc627e4d9d00432d6bbac65a923041edacf997d \ - --hash=sha256:baaf55442359053c7d62f6f8413a62adba3205119bcb6f49594894d8be47e5e3 \ - --hash=sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434 \ - --hash=sha256:be61f6fff406ca40e3b1d84716fde398fc08bc63dd96d15f3a14230a0973ed86 \ - --hash=sha256:bf49a3ae946a87083ef3a34c8f677ae4243f5b824bfc4c69672e72b3d6719d46 \ - --hash=sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319 \ - --hash=sha256:c75eb09e8d55bceb4367e83496ff8ef2bc7ea6960efb38e978e8073ea59ecb67 \ - --hash=sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c \ - --hash=sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169 \ - --hash=sha256:cbb0fef01f0c6b38cb0f39b1f78fc90b807e0e3c86a7ff3ce74ad77ce5c7880c \ - --hash=sha256:cde9a2ecd91668bcb7f077c4966d8ceddb60af01b52e6e3e2680e4cf00ad1a59 \ - --hash=sha256:cff6d44cb13d39db2663a22b22305d10855efa0fa8015ddeacc40bc59b9d8107 \ - --hash=sha256:d1009abedb49ae95b136a8904a3f71b342f849ffeced2d3747bf29caeda218c4 \ - --hash=sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a \ - --hash=sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb \ - --hash=sha256:d7504f2b476d21653e4d143f44a175f7f751cd41233525312696c76aa3dbb23f \ - --hash=sha256:dbf507e9ef5688bada447a24d68b4b58dd389ba93b7afc065a2ba892bea54769 \ - --hash=sha256:dc52310451fc7c629e13c4e061cbe2dd01684d91f2f8ee2821b083c58bd72432 \ - --hash=sha256:dd00607bffbf30250fe108065f07453ec124dbf223420f57f5e749b04295e090 \ - --hash=sha256:dda608c88cf709b1d406bdfcd84d8d63cff7c9e577a403c6108ce8ce9dcc8764 \ - --hash=sha256:debe9c4f41c32990771be5c22b56f810659f9ddf3d63f67abfdcaa2c6c9c5c1d \ - --hash=sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4 \ - --hash=sha256:e0fd068364a6759bc794459f0a735ab151d11304346332489c7972bacbe9e72b \ - --hash=sha256:e4c53f8347cd4200f0d70a48ad059cabaf24f5adc6ba08622a23423bc7efa10d \ - --hash=sha256:e5723c01a56c5028c807c701aa66722916d2747ad737a046853f6c46f4875543 \ - --hash=sha256:e7b0460976dc75cb87ad9cc1f9899a4b97751e7d4e77ab840fc9b6d377b8fd24 \ - --hash=sha256:e9d9a4d06d3481eab79803beb4d9bd6f6a8e781ec078ac70d7ef2dcc29d1bea5 \ - --hash=sha256:ead11956716a940c1abc816b7df3fa2b84d06eaed8832ca32f5c5e058c65506b \ - --hash=sha256:ed5f69ce7be7902e5c70ea19eb72d20abf7d725ab5d49777d696e32d4fc1811d \ - --hash=sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b \ - --hash=sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6 \ - --hash=sha256:f514f6474e04179d3d33175ed3f3e31434d3130d42ec153540d5b157deefd735 \ - --hash=sha256:f69f57305656a4852f2a7203efc661d8c042e6cc67f7acd97d8667fb448a426e \ - --hash=sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28 \ - --hash=sha256:fb4948814a2a98e3912505f09c9e7493b1506226afb1f881825368d6fb776ee3 \ - --hash=sha256:fda207c815b253e34f7e1909840fd14299567b1c0eb4908f8c2ce01a41265401 \ - --hash=sha256:fe8f8f5e70e6dbdfca9882cd9deaac058729bcf323cf7a58660901e55c9c94f6 \ - --hash=sha256:fffc45637bcd6538de8b85f51e3df3223e4ad89bccbfca0481c08c7fc8b7ed7d +yarl==1.24.2 \ + --hash=sha256:0063adad533e57171b79db3943b229d40dfafeeee579767f96541f106bac5f1b \ + --hash=sha256:044a09d8401fcf8681977faef6d286b8ade1e2d2e9dceda175d1cfa5ca496f30 \ + --hash=sha256:081c2bf54efe03774d0311172bc04fedf9ca01e644d4cd8c805688e527209bdc \ + --hash=sha256:08d3a33218e0c64393e7610284e770409a9c31c429b078bcb24096ed0a783b8f \ + --hash=sha256:0a6377060e7927187a42b7eb202090cbe2b34933a4eeaf90e3bd9e33432e5cae \ + --hash=sha256:0c3063e5c0a8e8e62fae6c2596fa01da1561e4cd1da6fec5789f5cf99a8aefd8 \ + --hash=sha256:15c0b5e49d3c44e2a0b93e6a49476c5edad0a7686b92c395765a7ea775572a75 \ + --hash=sha256:17076578bce0049a5ce57d14ad1bded391b68a3b213e9b81b0097b090244999a \ + --hash=sha256:1a97e42c8a2233f2f279ecadd9e4a037bcb5d813b78435e8eedd4db5a9e9708c \ + --hash=sha256:1e831894be7c2954240e49791fa4b50c05a0dc881de2552cfe3ffd8631c7f461 \ + --hash=sha256:204e7a61ce99919c0de1bf904ab5d7aa188a129ea8f690a8f76cfb6e2844dc44 \ + --hash=sha256:221ce1dd921ac4f603957f17d7c18c5cc0797fbb52f156941f92e04605d1d67b \ + --hash=sha256:246d32a53a947c8f0189f5d699cbd4c7036de45d9359e13ba238d1239678c727 \ + --hash=sha256:2783d9226db8797636cd6896e4de81feed252d1db72265686c9558d97a4d94b9 \ + --hash=sha256:297a2fe352ecf858b30a98f87948746ec16f001d279f84aebdbd3bd965e2f1bd \ + --hash=sha256:2a263e76b97bc42bdcd7c5f4953dec1f7cd62a1112fa7f869e57255229390d67 \ + --hash=sha256:2d07d21d0bc4b17558e8de0b02fbfdf1e347d3bb3699edd00bb92e7c57925420 \ + --hash=sha256:3065657c80a2321225e804048597ad55658a7e76b32d6f5ee4074d04c50401db \ + --hash=sha256:310fc687f7b2044ec54e372c8cbe923bb88f5c37bded0d3079e5791c2fc3cf50 \ + --hash=sha256:33a29b5d00ccbf3219bb3e351d7875739c19481e030779f48cc46a7a71681a9b \ + --hash=sha256:34263e2fa8fb5bb63a0d97706cda38edbad62fddb58c7f12d6acbc092812aa50 \ + --hash=sha256:349de4701dc3760b6e876628423a8f147ef4f5599d10aba1e10702075d424ed9 \ + --hash=sha256:36348bebb147b83818b9d7e673ea4debc75970afc6ffdc7e3975ad05ce5a58c1 \ + --hash=sha256:374423f70754a2c96942ede36a29d37dc6b0cb8f92f8d009ddf3ed78d3da5488 \ + --hash=sha256:3b075301a2836a0e297b1b658cb6d6135df535d62efefdd60366bd589c2c82f2 \ + --hash=sha256:3f6d2c216318f8f32038ca3f72501ba08536f0fd18a36e858836b121b2deed9f \ + --hash=sha256:47a55d6cf6db2f401017a9e96e5288844e5051911fb4e0c8311a3980f5e59a7d \ + --hash=sha256:49016d82f032b1bd1e10b01078a7d29ae71bf468eeae0ea22df8bab691e60003 \ + --hash=sha256:491ac9141decf49ee8030199e1ee251cdff0e131f25678817ff6aa5f837a3536 \ + --hash=sha256:4b156914620f0b9d78dc1adb3751141daee561cfec796088abb89ed49d220f1a \ + --hash=sha256:4b85b8825e631295ff4bc8943f7471d54c533a9360bbe15ebb38e018b555bb8a \ + --hash=sha256:4da31a5512ed1729ca8d8aacde3f7faeb8843cde3165d6bcf7f88f74f17bb8aa \ + --hash=sha256:4fb1ac3fc5fecd8ae7453ea237e4d22b49befa70266dfe1629924245c21a0c7f \ + --hash=sha256:50713f1d4d6be6375bb178bb43d140ee1acb8abe589cd723320b7925a275be1e \ + --hash=sha256:507cc19f0b45454e2d6dcd62ff7d062b9f77a2812404e62dbdaec05b50faa035 \ + --hash=sha256:5249a113065c2b7a958bc699759e359cd61cfc81e3069662208f48f191b7ed12 \ + --hash=sha256:533ded4dceb5f1f3da7906244f4e82cf46cfd40d84c69a1faf5ac506aa65ecbe \ + --hash=sha256:5cb0f995a901c36be096ccbf4c673591c2faabbe96279598ffaec8c030f85bf4 \ + --hash=sha256:5d699376c4ca3cba49bbfae3a05b5b70ded572937171ce1e0b8d87118e2ba294 \ + --hash=sha256:5ec8356b8a6afcf81fc7aeeef13b1ff7a49dec00f313394bbb9e83830d32ccd7 \ + --hash=sha256:5f3224db28173a00d7afacdee07045cc4673dfab2b15492c7ae10deddbece761 \ + --hash=sha256:60de6742447fbbf697f16f070b8a443f1b5fe6ca3826fbef9fe70ecd5328e643 \ + --hash=sha256:64480fb3e4d4ed9ed71c48a91a477384fc342a50ca30071d2f8a88d51d9c9413 \ + --hash=sha256:68cf6eacd6028ef1142bc4b48376b81566385ca6f9e7dde3b0fa91be08ffcb57 \ + --hash=sha256:6b208bb939099b4b297438da4e9b25357f0b1c791888669b963e45b203ea9f36 \ + --hash=sha256:73e68edf6dfd5f73f9ca127d84e2a6f9213c65bdffb736bda19524c0564fcd14 \ + --hash=sha256:7b3a85525f6e7eeabcfdd372862b21ee1915db1b498a04e8bf0e389b607ff0bd \ + --hash=sha256:7b54b9c67c2b06bd7b9a77253d242124b9c95d2c02def5a1144001ee547dd9d5 \ + --hash=sha256:7d37fb7c38f2b6edab0f845c4f85148d4c44204f52bc127021bd2bc9fdbf1656 \ + --hash=sha256:7dafe10c12ddd4d120d528c4b5599c953bd7b12845347d507b95451195bb6cad \ + --hash=sha256:7e7ebcdef69dec6c6451e616f32b622a6d4a2e92b445c992f7c8e5274a6bbc4c \ + --hash=sha256:7f4425fa244fbf530b006d0c5f79ce920114cfff5b4f5f6056e669f8e160fdc0 \ + --hash=sha256:810e19b685c8c3c5862f6a38160a1f4e4c0916c9390024ec347b6157a45a0992 \ + --hash=sha256:819ca24f8eafcfb683c1bd5f44f2f488cea1274eb8944731ffd2e1f10f619342 \ + --hash=sha256:822519b64cf0b474f1a0aaef1dc621438ea46bb77c94df97a5b4d213a7d8a8b1 \ + --hash=sha256:8372a2b976cf70654b2be6619ab6068acabb35f724c0fda7b277fbf53d66a5cf \ + --hash=sha256:84f9670b89f34db07f81e53aee83e0b938a3412329d51c8f922488be7fcc4024 \ + --hash=sha256:863297ddede92ee49024e9a9b11ecb59f310ca85b60d8537f56bed9bbb5b1986 \ + --hash=sha256:86746bef442aa479107fe28132e1277237f9c24c2f00b0b0cf22b3ee0904f2bb \ + --hash=sha256:8ae44649b00947634ab0dab2a374a638f52923a6e67083f2c156cd5cbd1a881d \ + --hash=sha256:8cec2a38d70edc10e0e856ceda886af5327a017ccbde8e1de1bd44d300357543 \ + --hash=sha256:8d027d56f1035e339d1001ac33eceab5b2ec8e42e449787bb75e289fb9a5cd1d \ + --hash=sha256:904065e6e85b1fa54d0d87438bd58c14c0bad97aad654ad1077fd9d87e8478ed \ + --hash=sha256:91e72cf093fd833483a97ee648e0c053c7c629f51ff4a0e7edd84f806b0c5617 \ + --hash=sha256:990de4f680b1c217e77ff0d6aa0029f9eb79889c11fb3e9a3942c7eba29c1996 \ + --hash=sha256:9ac374123c6fd7abf64d1fec93962b0bd4ee2c19751755a762a72dd96c0378f8 \ + --hash=sha256:a1cab588b4fa14bea2e55ebea27478adfb05372f47573738e1acc4a36c0b05d2 \ + --hash=sha256:a296ca617f2d25fbceafb962b88750d627e5984e75732c712154d058ae8d79a3 \ + --hash=sha256:a46d1ab4ba4d32e6dc80daf8a28ce0bd83d08df52fbc32f3e288663427734535 \ + --hash=sha256:a4f4d6cd615823bfc7fb7e9b5987c3f41666371d870d51058f77e2680fbe9630 \ + --hash=sha256:a7624b1ca46ca5d7b864ef0d2f8efe3091454085ee1855b4e992314529972215 \ + --hash=sha256:a9532c57211730c515341af11fef6e9b61d157487272a096d0c04da445642592 \ + --hash=sha256:abb2759733d63a28b4956500a5dd57140f26486c92b2caedfb964ab7d9b79dbf \ + --hash=sha256:abb8ec0323b80161e3802da3150ef660b41d0e9be2048b76a363d93eee992c2b \ + --hash=sha256:acf93187c3710e422368eb768aee98db551ec7c85adc250207a95c16548ab7ac \ + --hash=sha256:afb00d7fd8e0f285ca29a44cc50df2d622ff2f7a6d933fa641577b5f9d5f3db0 \ + --hash=sha256:b3177bc0a768ef3bacceb4f272632990b7bea352f1b2f1eee9d6d6ff16516f92 \ + --hash=sha256:b32c37a7a337e90822c45797bf3d79d60875cfcccd3ecc80e9f453d87026c122 \ + --hash=sha256:b6067060d9dc594899ba83e6db6c48c68d1e494a6dab158156ed86977ca7bcb1 \ + --hash=sha256:b975866c184564c827e0877380f0dae57dcca7e52782128381b72feff6dfceb8 \ + --hash=sha256:c4c17bad5a530912d2111825d3f05e89bab2dd376aaa8cbc77e449e6db63e576 \ + --hash=sha256:c557165320d6244ebe3a02431b2a201a20080e02f41f0cfa0ccc47a183765da8 \ + --hash=sha256:cb84b80d88e19ede158619b80813968713d8d008b0e2497a576e6a0557d50712 \ + --hash=sha256:cdfcce633b4a4bb8281913c57fcafd4b5933fbc19111a5e3930bbd299d6102f1 \ + --hash=sha256:d162677af8d5d3d6ebab8394b021f4d041ac107a4b705873148a77a49dc9e1b2 \ + --hash=sha256:d1dd47a22843b212baa8d74f37796815d43bd046b42a0f41e9da433386c3136b \ + --hash=sha256:e196952aacaf3b232e265ff02980b64d483dc0972bd49bcb061171ff22ac203a \ + --hash=sha256:e26acf20c26cb4fefc631fdb75aca2a6b8fa8b7b5d7f204fb6a8f1e63c706f53 \ + --hash=sha256:e30dd55825dc554ec5b66a94953b8eda8745926514c5089dfcacecb9c99b5bd1 \ + --hash=sha256:e434a45ce2e7a947f951fc5a8944c8cc080b7e59f9c50ae80fd39107cf88126d \ + --hash=sha256:e51b2cf5ec89a8b8470177641ed62a3ba22d74e1e898e06ad53aa77972487208 \ + --hash=sha256:e7484b9361ed222ee1ca5b4337aa4cbdcc4618ce5aff57d9ef1582fd95893fc0 \ + --hash=sha256:e7977781f83638a4c73e0f88425563d70173e0dfd90ac006a45c65036293ee3c \ + --hash=sha256:e89418f65eda18f99030386305bd44d7d504e328a7945db1ead514fbe03a0607 \ + --hash=sha256:ec87ccc31bd21db7ad009d8572c127c1000f268517618a4cc09adba3c2a7f21c \ + --hash=sha256:ee8e3fb34513e8dc082b586ef4910c98335d43a6fab688cd44d4851bacfce3e8 \ + --hash=sha256:f408eace7e22a68b467a0562e0d27d322f91fe3eaaa6f466b962c6cfaea9fa39 \ + --hash=sha256:f4b0352fd41fd34b6651934606268816afd6914d09626f9bcbbf018edb0afb3f \ + --hash=sha256:f5f0cbb112838a4a293985b6ed73948a547dadcc1ba6d2089938e7abdedceef8 \ + --hash=sha256:f5f5c6ec23a9043f2d139cc072f53dd23168d202a334b9b2fda8de4c3e890d90 \ + --hash=sha256:f8fdbcff8b2c7c9284e60c196f693588598ddcee31e11c18e14949ce44519d45 \ + --hash=sha256:f9312b3c02d9b3d23840f67952913c9c8721d7f1b7db305289faefa878f364c2 \ + --hash=sha256:f9a1e9b622ca284143aab5d885848686dcd85453bb1ca9abcdb7503e64dc0056 \ + --hash=sha256:fecd17873a096036c1c87ab3486f1aef7f269ada7f23f7f856f93b1cc7744f14 # via aiohttp diff --git a/packages/gapic-generator/setup.py b/packages/gapic-generator/setup.py index da2cccde365a..d85de3034dfe 100644 --- a/packages/gapic-generator/setup.py +++ b/packages/gapic-generator/setup.py @@ -61,7 +61,7 @@ author="Google LLC", author_email="googleapis-packages@google.com", license="Apache-2.0", - packages=setuptools.find_namespace_packages(exclude=["docs", "tests"]), + packages=setuptools.find_namespace_packages(include=["gapic*"]), url=url, classifiers=[ release_status, diff --git a/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py b/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py index 590b6fa1c615..b659b748cdf4 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py +++ b/packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -111,28 +115,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "cloudasset.googleapis.com" @@ -156,18 +139,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -423,12 +395,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = AssetServiceClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -441,13 +408,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -464,16 +425,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = AssetServiceClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = AssetServiceClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = AssetServiceClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + AssetServiceClient._DEFAULT_UNIVERSE, + AssetServiceClient.DEFAULT_MTLS_ENDPOINT, + AssetServiceClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -489,14 +452,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = AssetServiceClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + AssetServiceClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -611,12 +571,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/asset/noxfile.py b/packages/gapic-generator/tests/integration/goldens/asset/noxfile.py index 09d28712c73c..3064208f8d41 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/noxfile.py +++ b/packages/gapic-generator/tests/integration/goldens/asset/noxfile.py @@ -247,9 +247,9 @@ def install_unittest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=ALL_PYTHON) @@ -265,6 +265,15 @@ def unit(session, protobuf_implementation): ) install_unittest_dependencies(session, "-c", constraints_path) + # Override google-api-core with the local version from source if running in the monorepo + google_api_core_dir = next( + (str(p / "packages" / "google-api-core") for p in CURRENT_DIRECTORY.parents if (p / "packages" / "google-api-core").exists()), + None + ) + if google_api_core_dir: + session.run("pip", "uninstall", "google-api-core", "-y") + session.install("-e", google_api_core_dir, "--no-deps") + # Run py.test against the unit tests. session.run( "py.test", @@ -309,9 +318,9 @@ def install_systemtest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) @@ -374,7 +383,7 @@ def cover(session): def docs(session): """Build the docs for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -407,7 +416,7 @@ def docs(session): def docfx(session): """Build the docfx yaml files for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -463,7 +472,7 @@ def prerelease_deps(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES @@ -564,7 +573,7 @@ def prerelease_deps(session, protobuf_implementation): ) -@nox.session(python=PREVIEW_PYTHON_VERSION) +@nox.session(python=ALL_PYTHON) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -575,7 +584,7 @@ def core_deps_from_source(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES diff --git a/packages/gapic-generator/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py b/packages/gapic-generator/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py index ea110a38acc3..56bcae04fc43 100755 --- a/packages/gapic-generator/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py +++ b/packages/gapic-generator/tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py @@ -121,197 +121,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert AssetServiceClient._get_default_mtls_endpoint(None) is None - assert AssetServiceClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert AssetServiceClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert AssetServiceClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert AssetServiceClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert AssetServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert AssetServiceClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert AssetServiceClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert AssetServiceClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert AssetServiceClient._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - AssetServiceClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert AssetServiceClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert AssetServiceClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert AssetServiceClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert AssetServiceClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - AssetServiceClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert AssetServiceClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert AssetServiceClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert AssetServiceClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert AssetServiceClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert AssetServiceClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - AssetServiceClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert AssetServiceClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert AssetServiceClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert AssetServiceClient._get_client_cert_source(None, False) is None - assert AssetServiceClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert AssetServiceClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert AssetServiceClient._get_client_cert_source(None, True) is mock_default_cert_source - assert AssetServiceClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(AssetServiceClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(AssetServiceClient)) -@mock.patch.object(AssetServiceAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(AssetServiceAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = AssetServiceClient._DEFAULT_UNIVERSE - default_endpoint = AssetServiceClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = AssetServiceClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert AssetServiceClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert AssetServiceClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == AssetServiceClient.DEFAULT_MTLS_ENDPOINT - assert AssetServiceClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert AssetServiceClient._get_api_endpoint(None, None, default_universe, "always") == AssetServiceClient.DEFAULT_MTLS_ENDPOINT - assert AssetServiceClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == AssetServiceClient.DEFAULT_MTLS_ENDPOINT - assert AssetServiceClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert AssetServiceClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - AssetServiceClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert AssetServiceClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert AssetServiceClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert AssetServiceClient._get_universe_domain(None, None) == AssetServiceClient._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - AssetServiceClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -351,6 +171,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (AssetServiceClient, "grpc"), (AssetServiceAsyncClient, "grpc_asyncio"), @@ -696,6 +517,7 @@ def test_asset_service_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -743,6 +565,7 @@ def test_asset_service_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/services/iam_credentials/client.py b/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/services/iam_credentials/client.py index 4ad970da32e9..c1c49085c3eb 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/services/iam_credentials/client.py +++ b/packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/services/iam_credentials/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -114,28 +118,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "iamcredentials.googleapis.com" @@ -159,18 +142,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -360,12 +332,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = IAMCredentialsClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -378,13 +345,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -401,16 +362,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = IAMCredentialsClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = IAMCredentialsClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = IAMCredentialsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + IAMCredentialsClient._DEFAULT_UNIVERSE, + IAMCredentialsClient.DEFAULT_MTLS_ENDPOINT, + IAMCredentialsClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -426,14 +389,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = IAMCredentialsClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + IAMCredentialsClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -548,12 +508,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/noxfile.py b/packages/gapic-generator/tests/integration/goldens/credentials/noxfile.py index 65e26efe21d3..0bda04d7bab3 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/noxfile.py +++ b/packages/gapic-generator/tests/integration/goldens/credentials/noxfile.py @@ -247,9 +247,9 @@ def install_unittest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=ALL_PYTHON) @@ -265,6 +265,15 @@ def unit(session, protobuf_implementation): ) install_unittest_dependencies(session, "-c", constraints_path) + # Override google-api-core with the local version from source if running in the monorepo + google_api_core_dir = next( + (str(p / "packages" / "google-api-core") for p in CURRENT_DIRECTORY.parents if (p / "packages" / "google-api-core").exists()), + None + ) + if google_api_core_dir: + session.run("pip", "uninstall", "google-api-core", "-y") + session.install("-e", google_api_core_dir, "--no-deps") + # Run py.test against the unit tests. session.run( "py.test", @@ -309,9 +318,9 @@ def install_systemtest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) @@ -374,7 +383,7 @@ def cover(session): def docs(session): """Build the docs for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -407,7 +416,7 @@ def docs(session): def docfx(session): """Build the docfx yaml files for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -463,7 +472,7 @@ def prerelease_deps(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES @@ -564,7 +573,7 @@ def prerelease_deps(session, protobuf_implementation): ) -@nox.session(python=PREVIEW_PYTHON_VERSION) +@nox.session(python=ALL_PYTHON) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -575,7 +584,7 @@ def core_deps_from_source(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES diff --git a/packages/gapic-generator/tests/integration/goldens/credentials/tests/unit/gapic/credentials_v1/test_iam_credentials.py b/packages/gapic-generator/tests/integration/goldens/credentials/tests/unit/gapic/credentials_v1/test_iam_credentials.py index 14a6074a40f9..fdcd65e58074 100755 --- a/packages/gapic-generator/tests/integration/goldens/credentials/tests/unit/gapic/credentials_v1/test_iam_credentials.py +++ b/packages/gapic-generator/tests/integration/goldens/credentials/tests/unit/gapic/credentials_v1/test_iam_credentials.py @@ -111,197 +111,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert IAMCredentialsClient._get_default_mtls_endpoint(None) is None - assert IAMCredentialsClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert IAMCredentialsClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert IAMCredentialsClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert IAMCredentialsClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert IAMCredentialsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert IAMCredentialsClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert IAMCredentialsClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert IAMCredentialsClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert IAMCredentialsClient._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - IAMCredentialsClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert IAMCredentialsClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert IAMCredentialsClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert IAMCredentialsClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert IAMCredentialsClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - IAMCredentialsClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert IAMCredentialsClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert IAMCredentialsClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert IAMCredentialsClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert IAMCredentialsClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert IAMCredentialsClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - IAMCredentialsClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert IAMCredentialsClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert IAMCredentialsClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert IAMCredentialsClient._get_client_cert_source(None, False) is None - assert IAMCredentialsClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert IAMCredentialsClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert IAMCredentialsClient._get_client_cert_source(None, True) is mock_default_cert_source - assert IAMCredentialsClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(IAMCredentialsClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(IAMCredentialsClient)) -@mock.patch.object(IAMCredentialsAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(IAMCredentialsAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = IAMCredentialsClient._DEFAULT_UNIVERSE - default_endpoint = IAMCredentialsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = IAMCredentialsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert IAMCredentialsClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert IAMCredentialsClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == IAMCredentialsClient.DEFAULT_MTLS_ENDPOINT - assert IAMCredentialsClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert IAMCredentialsClient._get_api_endpoint(None, None, default_universe, "always") == IAMCredentialsClient.DEFAULT_MTLS_ENDPOINT - assert IAMCredentialsClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == IAMCredentialsClient.DEFAULT_MTLS_ENDPOINT - assert IAMCredentialsClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert IAMCredentialsClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - IAMCredentialsClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert IAMCredentialsClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert IAMCredentialsClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert IAMCredentialsClient._get_universe_domain(None, None) == IAMCredentialsClient._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - IAMCredentialsClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -341,6 +161,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (IAMCredentialsClient, "grpc"), (IAMCredentialsAsyncClient, "grpc_asyncio"), @@ -686,6 +507,7 @@ def test_iam_credentials_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -733,6 +555,7 @@ def test_iam_credentials_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/services/eventarc/client.py b/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/services/eventarc/client.py index 7255d3c91709..85a6cc3a50bc 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/services/eventarc/client.py +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/services/eventarc/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -132,28 +136,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "eventarc.googleapis.com" @@ -177,18 +160,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -543,12 +515,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = EventarcClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -561,13 +528,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -584,16 +545,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = EventarcClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = EventarcClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = EventarcClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + EventarcClient._DEFAULT_UNIVERSE, + EventarcClient.DEFAULT_MTLS_ENDPOINT, + EventarcClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -609,14 +572,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = EventarcClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + EventarcClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -731,12 +691,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/noxfile.py b/packages/gapic-generator/tests/integration/goldens/eventarc/noxfile.py index 42b2349e2cc1..170d722061ba 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/noxfile.py +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/noxfile.py @@ -247,9 +247,9 @@ def install_unittest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=ALL_PYTHON) @@ -265,6 +265,15 @@ def unit(session, protobuf_implementation): ) install_unittest_dependencies(session, "-c", constraints_path) + # Override google-api-core with the local version from source if running in the monorepo + google_api_core_dir = next( + (str(p / "packages" / "google-api-core") for p in CURRENT_DIRECTORY.parents if (p / "packages" / "google-api-core").exists()), + None + ) + if google_api_core_dir: + session.run("pip", "uninstall", "google-api-core", "-y") + session.install("-e", google_api_core_dir, "--no-deps") + # Run py.test against the unit tests. session.run( "py.test", @@ -309,9 +318,9 @@ def install_systemtest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) @@ -374,7 +383,7 @@ def cover(session): def docs(session): """Build the docs for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -407,7 +416,7 @@ def docs(session): def docfx(session): """Build the docfx yaml files for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -463,7 +472,7 @@ def prerelease_deps(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES @@ -564,7 +573,7 @@ def prerelease_deps(session, protobuf_implementation): ) -@nox.session(python=PREVIEW_PYTHON_VERSION) +@nox.session(python=ALL_PYTHON) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -575,7 +584,7 @@ def core_deps_from_source(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES diff --git a/packages/gapic-generator/tests/integration/goldens/eventarc/tests/unit/gapic/eventarc_v1/test_eventarc.py b/packages/gapic-generator/tests/integration/goldens/eventarc/tests/unit/gapic/eventarc_v1/test_eventarc.py index 533e401eb1e7..41695e70c76c 100755 --- a/packages/gapic-generator/tests/integration/goldens/eventarc/tests/unit/gapic/eventarc_v1/test_eventarc.py +++ b/packages/gapic-generator/tests/integration/goldens/eventarc/tests/unit/gapic/eventarc_v1/test_eventarc.py @@ -142,197 +142,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert EventarcClient._get_default_mtls_endpoint(None) is None - assert EventarcClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert EventarcClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert EventarcClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert EventarcClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert EventarcClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert EventarcClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert EventarcClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert EventarcClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert EventarcClient._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - EventarcClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert EventarcClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert EventarcClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert EventarcClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert EventarcClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - EventarcClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert EventarcClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert EventarcClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert EventarcClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert EventarcClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert EventarcClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - EventarcClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert EventarcClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert EventarcClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert EventarcClient._get_client_cert_source(None, False) is None - assert EventarcClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert EventarcClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert EventarcClient._get_client_cert_source(None, True) is mock_default_cert_source - assert EventarcClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(EventarcClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(EventarcClient)) -@mock.patch.object(EventarcAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(EventarcAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = EventarcClient._DEFAULT_UNIVERSE - default_endpoint = EventarcClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = EventarcClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert EventarcClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert EventarcClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == EventarcClient.DEFAULT_MTLS_ENDPOINT - assert EventarcClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert EventarcClient._get_api_endpoint(None, None, default_universe, "always") == EventarcClient.DEFAULT_MTLS_ENDPOINT - assert EventarcClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == EventarcClient.DEFAULT_MTLS_ENDPOINT - assert EventarcClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert EventarcClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - EventarcClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert EventarcClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert EventarcClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert EventarcClient._get_universe_domain(None, None) == EventarcClient._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - EventarcClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -372,6 +192,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (EventarcClient, "grpc"), (EventarcAsyncClient, "grpc_asyncio"), @@ -717,6 +538,7 @@ def test_eventarc_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -764,6 +586,7 @@ def test_eventarc_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py index 15922e6d865a..2efa8db56ce2 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -107,28 +111,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -152,18 +135,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -419,12 +391,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = ConfigServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -437,13 +404,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -460,16 +421,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = ConfigServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = ConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = ConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + ConfigServiceV2Client._DEFAULT_UNIVERSE, + ConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT, + ConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -485,14 +448,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = ConfigServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + ConfigServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -604,12 +564,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py index e89762755eda..425e8bcb4a79 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -104,28 +108,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -149,18 +132,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -350,12 +322,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = LoggingServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -368,13 +335,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -391,16 +352,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = LoggingServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + LoggingServiceV2Client._DEFAULT_UNIVERSE, + LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT, + LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -416,14 +379,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = LoggingServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + LoggingServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -535,12 +495,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py index 90e9355f8c26..5c73976529c7 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -105,28 +109,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -150,18 +133,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -351,12 +323,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = MetricsServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -369,13 +336,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -392,16 +353,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = MetricsServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = MetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = MetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + MetricsServiceV2Client._DEFAULT_UNIVERSE, + MetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT, + MetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -417,14 +380,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = MetricsServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + MetricsServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -536,12 +496,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/logging/noxfile.py b/packages/gapic-generator/tests/integration/goldens/logging/noxfile.py index 09e4b345592a..c2e40d7498d2 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/noxfile.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/noxfile.py @@ -247,9 +247,9 @@ def install_unittest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=ALL_PYTHON) @@ -265,6 +265,15 @@ def unit(session, protobuf_implementation): ) install_unittest_dependencies(session, "-c", constraints_path) + # Override google-api-core with the local version from source if running in the monorepo + google_api_core_dir = next( + (str(p / "packages" / "google-api-core") for p in CURRENT_DIRECTORY.parents if (p / "packages" / "google-api-core").exists()), + None + ) + if google_api_core_dir: + session.run("pip", "uninstall", "google-api-core", "-y") + session.install("-e", google_api_core_dir, "--no-deps") + # Run py.test against the unit tests. session.run( "py.test", @@ -309,9 +318,9 @@ def install_systemtest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) @@ -374,7 +383,7 @@ def cover(session): def docs(session): """Build the docs for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -407,7 +416,7 @@ def docs(session): def docfx(session): """Build the docfx yaml files for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -463,7 +472,7 @@ def prerelease_deps(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES @@ -564,7 +573,7 @@ def prerelease_deps(session, protobuf_implementation): ) -@nox.session(python=PREVIEW_PYTHON_VERSION) +@nox.session(python=ALL_PYTHON) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -575,7 +584,7 @@ def core_deps_from_source(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES diff --git a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_config_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_config_service_v2.py index eada5b433c55..9b3669d92d16 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_config_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_config_service_v2.py @@ -112,197 +112,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert ConfigServiceV2Client._get_default_mtls_endpoint(None) is None - assert ConfigServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert ConfigServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert ConfigServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert ConfigServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert ConfigServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert ConfigServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert ConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert ConfigServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert ConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - ConfigServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert ConfigServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert ConfigServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert ConfigServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert ConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - ConfigServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert ConfigServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert ConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert ConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert ConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert ConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - ConfigServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert ConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert ConfigServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert ConfigServiceV2Client._get_client_cert_source(None, False) is None - assert ConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert ConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert ConfigServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert ConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(ConfigServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(ConfigServiceV2Client)) -@mock.patch.object(ConfigServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(ConfigServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = ConfigServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = ConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = ConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert ConfigServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert ConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == ConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert ConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert ConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == ConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert ConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == ConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert ConfigServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert ConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - ConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert ConfigServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert ConfigServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert ConfigServiceV2Client._get_universe_domain(None, None) == ConfigServiceV2Client._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - ConfigServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -342,6 +162,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (ConfigServiceV2Client, "grpc"), (ConfigServiceV2AsyncClient, "grpc_asyncio"), @@ -674,6 +495,7 @@ def test_config_service_v2_client_get_mtls_endpoint_and_cert_source(client_class for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -721,6 +543,7 @@ def test_config_service_v2_client_get_mtls_endpoint_and_cert_source(client_class for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_logging_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_logging_service_v2.py index 65559a5d1073..c01ac304f4bd 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_logging_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_logging_service_v2.py @@ -113,197 +113,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert LoggingServiceV2Client._get_default_mtls_endpoint(None) is None - assert LoggingServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert LoggingServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert LoggingServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - LoggingServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert LoggingServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - LoggingServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - LoggingServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert LoggingServiceV2Client._get_client_cert_source(None, False) is None - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert LoggingServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(LoggingServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(LoggingServiceV2Client)) -@mock.patch.object(LoggingServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(LoggingServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = LoggingServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert LoggingServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert LoggingServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert LoggingServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert LoggingServiceV2Client._get_universe_domain(None, None) == LoggingServiceV2Client._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - LoggingServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -343,6 +163,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (LoggingServiceV2Client, "grpc"), (LoggingServiceV2AsyncClient, "grpc_asyncio"), @@ -675,6 +496,7 @@ def test_logging_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -722,6 +544,7 @@ def test_logging_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_metrics_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_metrics_service_v2.py index 90cdab2be2b2..0a85f0809de5 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_metrics_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_metrics_service_v2.py @@ -111,197 +111,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert MetricsServiceV2Client._get_default_mtls_endpoint(None) is None - assert MetricsServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert MetricsServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert MetricsServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert MetricsServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert MetricsServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert MetricsServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert MetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert MetricsServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert MetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - MetricsServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert MetricsServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert MetricsServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert MetricsServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert MetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - MetricsServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert MetricsServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert MetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert MetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert MetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert MetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - MetricsServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert MetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert MetricsServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert MetricsServiceV2Client._get_client_cert_source(None, False) is None - assert MetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert MetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert MetricsServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert MetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(MetricsServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(MetricsServiceV2Client)) -@mock.patch.object(MetricsServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(MetricsServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = MetricsServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = MetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = MetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert MetricsServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert MetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == MetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert MetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert MetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == MetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert MetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == MetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert MetricsServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert MetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - MetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert MetricsServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert MetricsServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert MetricsServiceV2Client._get_universe_domain(None, None) == MetricsServiceV2Client._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - MetricsServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -341,6 +161,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (MetricsServiceV2Client, "grpc"), (MetricsServiceV2AsyncClient, "grpc_asyncio"), @@ -673,6 +494,7 @@ def test_metrics_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -720,6 +542,7 @@ def test_metrics_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/config_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/config_service_v2/client.py index 61204cb87a52..f52ea0384e33 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/config_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/config_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -107,28 +111,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -152,18 +135,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -419,12 +391,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = BaseConfigServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -437,13 +404,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -460,16 +421,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = BaseConfigServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = BaseConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = BaseConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + BaseConfigServiceV2Client._DEFAULT_UNIVERSE, + BaseConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT, + BaseConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -485,14 +448,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = BaseConfigServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + BaseConfigServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -604,12 +564,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/logging_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/logging_service_v2/client.py index e89762755eda..425e8bcb4a79 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/logging_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/logging_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -104,28 +108,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -149,18 +132,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -350,12 +322,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = LoggingServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -368,13 +335,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -391,16 +352,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = LoggingServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + LoggingServiceV2Client._DEFAULT_UNIVERSE, + LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT, + LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -416,14 +379,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = LoggingServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + LoggingServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -535,12 +495,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/metrics_service_v2/client.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/metrics_service_v2/client.py index fa55137223d1..ccd616b54fa2 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/metrics_service_v2/client.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/metrics_service_v2/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -105,28 +109,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "logging.googleapis.com" @@ -150,18 +133,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -351,12 +323,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = BaseMetricsServiceV2Client._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -369,13 +336,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -392,16 +353,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = BaseMetricsServiceV2Client._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = BaseMetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = BaseMetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + BaseMetricsServiceV2Client._DEFAULT_UNIVERSE, + BaseMetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT, + BaseMetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -417,14 +380,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = BaseMetricsServiceV2Client._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + BaseMetricsServiceV2Client._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -536,12 +496,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/noxfile.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/noxfile.py index 09e4b345592a..c2e40d7498d2 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/noxfile.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/noxfile.py @@ -247,9 +247,9 @@ def install_unittest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=ALL_PYTHON) @@ -265,6 +265,15 @@ def unit(session, protobuf_implementation): ) install_unittest_dependencies(session, "-c", constraints_path) + # Override google-api-core with the local version from source if running in the monorepo + google_api_core_dir = next( + (str(p / "packages" / "google-api-core") for p in CURRENT_DIRECTORY.parents if (p / "packages" / "google-api-core").exists()), + None + ) + if google_api_core_dir: + session.run("pip", "uninstall", "google-api-core", "-y") + session.install("-e", google_api_core_dir, "--no-deps") + # Run py.test against the unit tests. session.run( "py.test", @@ -309,9 +318,9 @@ def install_systemtest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) @@ -374,7 +383,7 @@ def cover(session): def docs(session): """Build the docs for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -407,7 +416,7 @@ def docs(session): def docfx(session): """Build the docfx yaml files for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -463,7 +472,7 @@ def prerelease_deps(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES @@ -564,7 +573,7 @@ def prerelease_deps(session, protobuf_implementation): ) -@nox.session(python=PREVIEW_PYTHON_VERSION) +@nox.session(python=ALL_PYTHON) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -575,7 +584,7 @@ def core_deps_from_source(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_config_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_config_service_v2.py index 9eec837e6f58..c875df842e28 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_config_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_config_service_v2.py @@ -112,197 +112,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(None) is None - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert BaseConfigServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - BaseConfigServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert BaseConfigServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - BaseConfigServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert BaseConfigServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert BaseConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - BaseConfigServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert BaseConfigServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert BaseConfigServiceV2Client._get_client_cert_source(None, False) is None - assert BaseConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert BaseConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert BaseConfigServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert BaseConfigServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(BaseConfigServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(BaseConfigServiceV2Client)) -@mock.patch.object(BaseConfigServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(BaseConfigServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = BaseConfigServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = BaseConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = BaseConfigServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert BaseConfigServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert BaseConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == BaseConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert BaseConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == BaseConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == BaseConfigServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseConfigServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert BaseConfigServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - BaseConfigServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert BaseConfigServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert BaseConfigServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert BaseConfigServiceV2Client._get_universe_domain(None, None) == BaseConfigServiceV2Client._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - BaseConfigServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -342,6 +162,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (BaseConfigServiceV2Client, "grpc"), (BaseConfigServiceV2AsyncClient, "grpc_asyncio"), @@ -674,6 +495,7 @@ def test_base_config_service_v2_client_get_mtls_endpoint_and_cert_source(client_ for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -721,6 +543,7 @@ def test_base_config_service_v2_client_get_mtls_endpoint_and_cert_source(client_ for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_logging_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_logging_service_v2.py index 65559a5d1073..c01ac304f4bd 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_logging_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_logging_service_v2.py @@ -113,197 +113,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert LoggingServiceV2Client._get_default_mtls_endpoint(None) is None - assert LoggingServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert LoggingServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert LoggingServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert LoggingServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - LoggingServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert LoggingServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - LoggingServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert LoggingServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert LoggingServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - LoggingServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert LoggingServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert LoggingServiceV2Client._get_client_cert_source(None, False) is None - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert LoggingServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert LoggingServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(LoggingServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(LoggingServiceV2Client)) -@mock.patch.object(LoggingServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(LoggingServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = LoggingServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = LoggingServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert LoggingServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == LoggingServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert LoggingServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert LoggingServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - LoggingServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert LoggingServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert LoggingServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert LoggingServiceV2Client._get_universe_domain(None, None) == LoggingServiceV2Client._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - LoggingServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -343,6 +163,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (LoggingServiceV2Client, "grpc"), (LoggingServiceV2AsyncClient, "grpc_asyncio"), @@ -675,6 +496,7 @@ def test_logging_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -722,6 +544,7 @@ def test_logging_service_v2_client_get_mtls_endpoint_and_cert_source(client_clas for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_metrics_service_v2.py b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_metrics_service_v2.py index 310677b64bc6..939af86abac9 100755 --- a/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_metrics_service_v2.py +++ b/packages/gapic-generator/tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_metrics_service_v2.py @@ -111,197 +111,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(None) is None - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert BaseMetricsServiceV2Client._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - BaseMetricsServiceV2Client._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert BaseMetricsServiceV2Client._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - BaseMetricsServiceV2Client._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert BaseMetricsServiceV2Client._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - BaseMetricsServiceV2Client._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert BaseMetricsServiceV2Client._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert BaseMetricsServiceV2Client._get_client_cert_source(None, False) is None - assert BaseMetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, False) is None - assert BaseMetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert BaseMetricsServiceV2Client._get_client_cert_source(None, True) is mock_default_cert_source - assert BaseMetricsServiceV2Client._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(BaseMetricsServiceV2Client, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(BaseMetricsServiceV2Client)) -@mock.patch.object(BaseMetricsServiceV2AsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(BaseMetricsServiceV2AsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = BaseMetricsServiceV2Client._DEFAULT_UNIVERSE - default_endpoint = BaseMetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = BaseMetricsServiceV2Client._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert BaseMetricsServiceV2Client._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert BaseMetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == BaseMetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseMetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert BaseMetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "always") == BaseMetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseMetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == BaseMetricsServiceV2Client.DEFAULT_MTLS_ENDPOINT - assert BaseMetricsServiceV2Client._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert BaseMetricsServiceV2Client._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - BaseMetricsServiceV2Client._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert BaseMetricsServiceV2Client._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert BaseMetricsServiceV2Client._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert BaseMetricsServiceV2Client._get_universe_domain(None, None) == BaseMetricsServiceV2Client._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - BaseMetricsServiceV2Client._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -341,6 +161,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (BaseMetricsServiceV2Client, "grpc"), (BaseMetricsServiceV2AsyncClient, "grpc_asyncio"), @@ -673,6 +494,7 @@ def test_base_metrics_service_v2_client_get_mtls_endpoint_and_cert_source(client for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -720,6 +542,7 @@ def test_base_metrics_service_v2_client_get_mtls_endpoint_and_cert_source(client for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py b/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py index 33ccce478c8e..53d7c2c7e53b 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py +++ b/packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -142,28 +146,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "redis.googleapis.com" @@ -187,18 +170,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -388,12 +360,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = CloudRedisClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -406,13 +373,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -429,16 +390,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = CloudRedisClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = CloudRedisClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + CloudRedisClient._DEFAULT_UNIVERSE, + CloudRedisClient.DEFAULT_MTLS_ENDPOINT, + CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -454,14 +417,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = CloudRedisClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + CloudRedisClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -576,12 +536,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/redis/noxfile.py b/packages/gapic-generator/tests/integration/goldens/redis/noxfile.py index 9b3356dd1272..24f472be90cf 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/noxfile.py +++ b/packages/gapic-generator/tests/integration/goldens/redis/noxfile.py @@ -247,9 +247,9 @@ def install_unittest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=ALL_PYTHON) @@ -265,6 +265,15 @@ def unit(session, protobuf_implementation): ) install_unittest_dependencies(session, "-c", constraints_path) + # Override google-api-core with the local version from source if running in the monorepo + google_api_core_dir = next( + (str(p / "packages" / "google-api-core") for p in CURRENT_DIRECTORY.parents if (p / "packages" / "google-api-core").exists()), + None + ) + if google_api_core_dir: + session.run("pip", "uninstall", "google-api-core", "-y") + session.install("-e", google_api_core_dir, "--no-deps") + # Run py.test against the unit tests. session.run( "py.test", @@ -309,9 +318,9 @@ def install_systemtest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) @@ -374,7 +383,7 @@ def cover(session): def docs(session): """Build the docs for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -407,7 +416,7 @@ def docs(session): def docfx(session): """Build the docfx yaml files for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -463,7 +472,7 @@ def prerelease_deps(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES @@ -564,7 +573,7 @@ def prerelease_deps(session, protobuf_implementation): ) -@nox.session(python=PREVIEW_PYTHON_VERSION) +@nox.session(python=ALL_PYTHON) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -575,7 +584,7 @@ def core_deps_from_source(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES diff --git a/packages/gapic-generator/tests/integration/goldens/redis/tests/unit/gapic/redis_v1/test_cloud_redis.py b/packages/gapic-generator/tests/integration/goldens/redis/tests/unit/gapic/redis_v1/test_cloud_redis.py index 8ca1fb5194a6..090b4749df56 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis/tests/unit/gapic/redis_v1/test_cloud_redis.py +++ b/packages/gapic-generator/tests/integration/goldens/redis/tests/unit/gapic/redis_v1/test_cloud_redis.py @@ -129,197 +129,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert CloudRedisClient._get_default_mtls_endpoint(None) is None - assert CloudRedisClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert CloudRedisClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert CloudRedisClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - CloudRedisClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert CloudRedisClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert CloudRedisClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert CloudRedisClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - CloudRedisClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - CloudRedisClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert CloudRedisClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert CloudRedisClient._get_client_cert_source(None, False) is None - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert CloudRedisClient._get_client_cert_source(None, True) is mock_default_cert_source - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(CloudRedisClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(CloudRedisClient)) -@mock.patch.object(CloudRedisAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(CloudRedisAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = CloudRedisClient._DEFAULT_UNIVERSE - default_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert CloudRedisClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "always") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert CloudRedisClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert CloudRedisClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert CloudRedisClient._get_universe_domain(None, None) == CloudRedisClient._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - CloudRedisClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -359,6 +179,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (CloudRedisClient, "grpc"), (CloudRedisAsyncClient, "grpc_asyncio"), @@ -704,6 +525,7 @@ def test_cloud_redis_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -751,6 +573,7 @@ def test_cloud_redis_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/services/cloud_redis/client.py b/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/services/cloud_redis/client.py index 031573ef83d7..421adaf00fb1 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/services/cloud_redis/client.py +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/services/cloud_redis/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -27,6 +28,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -142,28 +146,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "redis.googleapis.com" @@ -187,18 +170,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -388,12 +360,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = CloudRedisClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -406,13 +373,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -429,16 +390,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = CloudRedisClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = CloudRedisClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + CloudRedisClient._DEFAULT_UNIVERSE, + CloudRedisClient.DEFAULT_MTLS_ENDPOINT, + CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -454,14 +417,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = CloudRedisClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + CloudRedisClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -576,12 +536,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/noxfile.py b/packages/gapic-generator/tests/integration/goldens/redis_selective/noxfile.py index 9b3356dd1272..24f472be90cf 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/noxfile.py +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/noxfile.py @@ -247,9 +247,9 @@ def install_unittest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=ALL_PYTHON) @@ -265,6 +265,15 @@ def unit(session, protobuf_implementation): ) install_unittest_dependencies(session, "-c", constraints_path) + # Override google-api-core with the local version from source if running in the monorepo + google_api_core_dir = next( + (str(p / "packages" / "google-api-core") for p in CURRENT_DIRECTORY.parents if (p / "packages" / "google-api-core").exists()), + None + ) + if google_api_core_dir: + session.run("pip", "uninstall", "google-api-core", "-y") + session.install("-e", google_api_core_dir, "--no-deps") + # Run py.test against the unit tests. session.run( "py.test", @@ -309,9 +318,9 @@ def install_systemtest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) @@ -374,7 +383,7 @@ def cover(session): def docs(session): """Build the docs for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -407,7 +416,7 @@ def docs(session): def docfx(session): """Build the docfx yaml files for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -463,7 +472,7 @@ def prerelease_deps(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES @@ -564,7 +573,7 @@ def prerelease_deps(session, protobuf_implementation): ) -@nox.session(python=PREVIEW_PYTHON_VERSION) +@nox.session(python=ALL_PYTHON) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -575,7 +584,7 @@ def core_deps_from_source(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES diff --git a/packages/gapic-generator/tests/integration/goldens/redis_selective/tests/unit/gapic/redis_v1/test_cloud_redis.py b/packages/gapic-generator/tests/integration/goldens/redis_selective/tests/unit/gapic/redis_v1/test_cloud_redis.py index 3f6b7aa521f3..94d8b62f62dc 100755 --- a/packages/gapic-generator/tests/integration/goldens/redis_selective/tests/unit/gapic/redis_v1/test_cloud_redis.py +++ b/packages/gapic-generator/tests/integration/goldens/redis_selective/tests/unit/gapic/redis_v1/test_cloud_redis.py @@ -129,197 +129,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert CloudRedisClient._get_default_mtls_endpoint(None) is None - assert CloudRedisClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert CloudRedisClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert CloudRedisClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert CloudRedisClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - CloudRedisClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert CloudRedisClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert CloudRedisClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert CloudRedisClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - CloudRedisClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert CloudRedisClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert CloudRedisClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - CloudRedisClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert CloudRedisClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert CloudRedisClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert CloudRedisClient._get_client_cert_source(None, False) is None - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert CloudRedisClient._get_client_cert_source(None, True) is mock_default_cert_source - assert CloudRedisClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(CloudRedisClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(CloudRedisClient)) -@mock.patch.object(CloudRedisAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(CloudRedisAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = CloudRedisClient._DEFAULT_UNIVERSE - default_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = CloudRedisClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert CloudRedisClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "always") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == CloudRedisClient.DEFAULT_MTLS_ENDPOINT - assert CloudRedisClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert CloudRedisClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - CloudRedisClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert CloudRedisClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert CloudRedisClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert CloudRedisClient._get_universe_domain(None, None) == CloudRedisClient._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - CloudRedisClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -359,6 +179,7 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] + @pytest.mark.parametrize("client_class,transport_name", [ (CloudRedisClient, "grpc"), (CloudRedisAsyncClient, "grpc_asyncio"), @@ -704,6 +525,7 @@ def test_cloud_redis_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -751,6 +573,7 @@ def test_cloud_redis_client_get_mtls_endpoint_and_cert_source(client_class): for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py index 5f79cf8e016a..685267bcea3d 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/services/storage_batch_operations/client.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # + from collections import OrderedDict from http import HTTPStatus import json @@ -20,7 +21,7 @@ import os import re from typing import Dict, Callable, Mapping, MutableMapping, MutableSequence, Optional, Sequence, Tuple, Type, Union, cast -import uuid +from google.api_core.gapic_v1 import _method_helpers import warnings from google.cloud.storagebatchoperations_v1 import gapic_version as package_version @@ -28,6 +29,9 @@ 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.gapic_v1 import _client_cert +from google.api_core.gapic_v1 import _config_helpers +from google.api_core.gapic_v1 import _routing 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 @@ -115,28 +119,7 @@ def _get_default_mtls_endpoint(api_endpoint) -> Optional[str]: Returns: Optional[str]: converted mTLS api endpoint. """ - if not api_endpoint: - return api_endpoint - - mtls_endpoint_re = re.compile( - r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" - ) - - m = mtls_endpoint_re.match(api_endpoint) - if m is None: - # Could not parse api_endpoint; return as-is. - return api_endpoint - - name, mtls, sandbox, googledomain = m.groups() - if mtls or not googledomain: - return api_endpoint - - if sandbox: - return api_endpoint.replace( - "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" - ) - - return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + return _routing.get_default_mtls_endpoint(api_endpoint) # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead. DEFAULT_ENDPOINT = "storagebatchoperations.googleapis.com" @@ -160,18 +143,7 @@ def _use_client_cert_effective(): ValueError: (If using a version of google-auth without should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) """ - # check if google-auth version supports should_use_client_cert for automatic mTLS enablement - if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER - return mtls.should_use_client_cert() - else: # pragma: NO COVER - # if unsupported, fallback to reading from env var - use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower() - if use_client_cert_str not in ("true", "false"): - raise ValueError( - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" - " either `true` or `false`" - ) - return use_client_cert_str == "true" + return _client_cert.use_client_cert_effective() @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): @@ -383,12 +355,7 @@ def _read_environment_variables(): google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT is not any of ["auto", "never", "always"]. """ - use_client_cert = StorageBatchOperationsClient._use_client_cert_effective() - use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() - universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") - if use_mtls_endpoint not in ("auto", "never", "always"): - raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`") - return use_client_cert, use_mtls_endpoint, universe_domain_env + return _config_helpers.read_environment_variables() @staticmethod def _get_client_cert_source(provided_cert_source, use_cert_flag): @@ -401,13 +368,7 @@ def _get_client_cert_source(provided_cert_source, use_cert_flag): Returns: bytes or None: The client cert source to be used by the client. """ - client_cert_source = None - if use_cert_flag: - if provided_cert_source: - client_cert_source = provided_cert_source - elif mtls.has_default_client_cert_source(): - client_cert_source = mtls.default_client_cert_source() - return client_cert_source + return _client_cert.get_client_cert_source(provided_cert_source, use_cert_flag) @staticmethod def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str: @@ -424,16 +385,18 @@ def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtl Returns: str: The API endpoint to be used by the client. """ - if api_override is not None: - api_endpoint = api_override - elif use_mtls_endpoint == "always" or (use_mtls_endpoint == "auto" and client_cert_source): - _default_universe = StorageBatchOperationsClient._DEFAULT_UNIVERSE - if universe_domain != _default_universe: - raise MutualTLSChannelError(f"mTLS is not supported in any universe other than {_default_universe}.") - api_endpoint = StorageBatchOperationsClient.DEFAULT_MTLS_ENDPOINT - else: - api_endpoint = StorageBatchOperationsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=universe_domain) - return api_endpoint + return cast( + str, + _routing.get_api_endpoint( + api_override, + client_cert_source, + universe_domain, + use_mtls_endpoint, + StorageBatchOperationsClient._DEFAULT_UNIVERSE, + StorageBatchOperationsClient.DEFAULT_MTLS_ENDPOINT, + StorageBatchOperationsClient._DEFAULT_ENDPOINT_TEMPLATE, + ), + ) @staticmethod def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_env: Optional[str]) -> str: @@ -449,14 +412,11 @@ def _get_universe_domain(client_universe_domain: Optional[str], universe_domain_ Raises: ValueError: If the universe domain is an empty string. """ - universe_domain = StorageBatchOperationsClient._DEFAULT_UNIVERSE - if client_universe_domain is not None: - universe_domain = client_universe_domain - elif universe_domain_env is not None: - universe_domain = universe_domain_env - if len(universe_domain.strip()) == 0: - raise ValueError("Universe Domain cannot be an empty string.") - return universe_domain + return _routing.get_universe_domain( + client_universe_domain, + universe_domain_env, + StorageBatchOperationsClient._DEFAULT_UNIVERSE, + ) def _validate_universe_domain(self): """Validates client's and credentials' universe domains are consistent. @@ -480,26 +440,7 @@ def _setup_request_id(request, field_name: str, is_proto3_optional: bool): field_name (str): The name of the field to populate. is_proto3_optional (bool): Whether the field is proto3 optional. """ - if isinstance(request, dict): - if is_proto3_optional: - if field_name not in request: - request[field_name] = str(uuid.uuid4()) - elif not request.get(field_name): - request[field_name] = str(uuid.uuid4()) - return - - if is_proto3_optional: - try: - # Pure protobuf messages - if not request.HasField(field_name): - setattr(request, field_name, str(uuid.uuid4())) - except (AttributeError, ValueError): - # Proto-plus messages or other objects - if field_name not in request: - setattr(request, field_name, str(uuid.uuid4())) - else: - if not getattr(request, field_name): - setattr(request, field_name, str(uuid.uuid4())) + _method_helpers.setup_request_id(request, field_name, is_proto3_optional) def _add_cred_info_for_auth_errors( self, @@ -601,12 +542,11 @@ def __init__(self, *, google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport creation failed for any reason. """ - self._client_options = client_options - if isinstance(self._client_options, dict): - self._client_options = client_options_lib.from_dict(self._client_options) - if self._client_options is None: - self._client_options = client_options_lib.ClientOptions() - self._client_options = cast(client_options_lib.ClientOptions, self._client_options) + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + self._client_options = cast(client_options_lib.ClientOptions, client_options) universe_domain_opt = getattr(self._client_options, 'universe_domain', None) diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/noxfile.py b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/noxfile.py index db370dd3dd0f..6112c788830b 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/noxfile.py +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/noxfile.py @@ -247,9 +247,9 @@ def install_unittest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=ALL_PYTHON) @@ -265,6 +265,15 @@ def unit(session, protobuf_implementation): ) install_unittest_dependencies(session, "-c", constraints_path) + # Override google-api-core with the local version from source if running in the monorepo + google_api_core_dir = next( + (str(p / "packages" / "google-api-core") for p in CURRENT_DIRECTORY.parents if (p / "packages" / "google-api-core").exists()), + None + ) + if google_api_core_dir: + session.run("pip", "uninstall", "google-api-core", "-y") + session.install("-e", google_api_core_dir, "--no-deps") + # Run py.test against the unit tests. session.run( "py.test", @@ -309,9 +318,9 @@ def install_systemtest_dependencies(session, *constraints): extras = [] if extras: - session.install("-e", f".[{','.join(extras)}]", *constraints) + session.install(f".[{','.join(extras)}]", *constraints) else: - session.install("-e", ".", *constraints) + session.install(".", *constraints) @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) @@ -374,7 +383,7 @@ def cover(session): def docs(session): """Build the docs for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -407,7 +416,7 @@ def docs(session): def docfx(session): """Build the docfx yaml files for this library.""" - session.install("-e", ".") + session.install(".") session.install( # We need to pin to specific versions of the `sphinxcontrib-*` packages # which still support sphinx 4.x. @@ -463,7 +472,7 @@ def prerelease_deps(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES @@ -564,7 +573,7 @@ def prerelease_deps(session, protobuf_implementation): ) -@nox.session(python=PREVIEW_PYTHON_VERSION) +@nox.session(python=ALL_PYTHON) @nox.parametrize( "protobuf_implementation", ["python", "upb"], @@ -575,7 +584,7 @@ def core_deps_from_source(session, protobuf_implementation): """ # Install all dependencies - session.install("-e", ".") + session.install(".") # Install dependencies for the unit test environment unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES diff --git a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py index 5c53e97f8d12..e4d3fbdddca1 100755 --- a/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py +++ b/packages/gapic-generator/tests/integration/goldens/storagebatchoperations/tests/unit/gapic/storagebatchoperations_v1/test_storage_batch_operations.py @@ -121,197 +121,17 @@ def set_event_loop(): asyncio.set_event_loop(None) -def test__get_default_mtls_endpoint(): - api_endpoint = "example.googleapis.com" - api_mtls_endpoint = "example.mtls.googleapis.com" - sandbox_endpoint = "example.sandbox.googleapis.com" - sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" - non_googleapi = "api.example.com" - custom_endpoint = ".custom" - - assert StorageBatchOperationsClient._get_default_mtls_endpoint(None) is None - assert StorageBatchOperationsClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint - assert StorageBatchOperationsClient._get_default_mtls_endpoint(api_mtls_endpoint) == api_mtls_endpoint - assert StorageBatchOperationsClient._get_default_mtls_endpoint(sandbox_endpoint) == sandbox_mtls_endpoint - assert StorageBatchOperationsClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) == sandbox_mtls_endpoint - assert StorageBatchOperationsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi - assert StorageBatchOperationsClient._get_default_mtls_endpoint(custom_endpoint) == custom_endpoint - -def test__read_environment_variables(): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert StorageBatchOperationsClient._read_environment_variables() == (True, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "auto", None) - +@pytest.fixture(scope="module", autouse=True) +def mock_mtls_env(): with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + os.environ, + { + "GOOGLE_API_USE_CLIENT_CERTIFICATE": "false", + "CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false", + }, ): - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with pytest.raises(ValueError) as excinfo: - StorageBatchOperationsClient._read_environment_variables() - assert ( - str(excinfo.value) - == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" - ) - else: - assert StorageBatchOperationsClient._read_environment_variables() == ( - False, - "auto", - None, - ) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "never", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "always", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "auto", None) - - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): - with pytest.raises(MutualTLSChannelError) as excinfo: - StorageBatchOperationsClient._read_environment_variables() - assert str(excinfo.value) == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" - - with mock.patch.dict(os.environ, {"GOOGLE_CLOUD_UNIVERSE_DOMAIN": "foo.com"}): - assert StorageBatchOperationsClient._read_environment_variables() == (False, "auto", "foo.com") - - -def test_use_client_cert_effective(): - # Test case 1: Test when `should_use_client_cert` returns True. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True): - assert StorageBatchOperationsClient._use_client_cert_effective() is True - - # Test case 2: Test when `should_use_client_cert` returns False. - # We mock the `should_use_client_cert` function to simulate a scenario where - # the google-auth library supports automatic mTLS and determines that a - # client certificate should NOT be used. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 3: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is True - - # Test case 4: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 5: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is True - - # Test case 6: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 7: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is True - - # Test case 8: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 9: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set. - # In this case, the method should return False, which is the default value. - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, clear=True): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 10: Test when `should_use_client_cert` is unavailable and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should raise a ValueError as the environment variable must be either - # "true" or "false". - if not hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - with pytest.raises(ValueError): - StorageBatchOperationsClient._use_client_cert_effective() - - # Test case 11: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value. - # The method should return False as the environment variable is set to an invalid value. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - - # Test case 12: Test when `should_use_client_cert` is available and the - # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also, - # the GOOGLE_API_CONFIG environment variable is unset. - if hasattr(google.auth.transport.mtls, "should_use_client_cert"): - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}): - with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}): - assert StorageBatchOperationsClient._use_client_cert_effective() is False - -def test__get_client_cert_source(): - mock_provided_cert_source = mock.Mock() - mock_default_cert_source = mock.Mock() - - assert StorageBatchOperationsClient._get_client_cert_source(None, False) is None - assert StorageBatchOperationsClient._get_client_cert_source(mock_provided_cert_source, False) is None - assert StorageBatchOperationsClient._get_client_cert_source(mock_provided_cert_source, True) == mock_provided_cert_source - - 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_default_cert_source): - assert StorageBatchOperationsClient._get_client_cert_source(None, True) is mock_default_cert_source - assert StorageBatchOperationsClient._get_client_cert_source(mock_provided_cert_source, "true") is mock_provided_cert_source - -@mock.patch.object(StorageBatchOperationsClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(StorageBatchOperationsClient)) -@mock.patch.object(StorageBatchOperationsAsyncClient, "_DEFAULT_ENDPOINT_TEMPLATE", modify_default_endpoint_template(StorageBatchOperationsAsyncClient)) -def test__get_api_endpoint(): - api_override = "foo.com" - mock_client_cert_source = mock.Mock() - default_universe = StorageBatchOperationsClient._DEFAULT_UNIVERSE - default_endpoint = StorageBatchOperationsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=default_universe) - mock_universe = "bar.com" - mock_endpoint = StorageBatchOperationsClient._DEFAULT_ENDPOINT_TEMPLATE.format(UNIVERSE_DOMAIN=mock_universe) - - assert StorageBatchOperationsClient._get_api_endpoint(api_override, mock_client_cert_source, default_universe, "always") == api_override - assert StorageBatchOperationsClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "auto") == StorageBatchOperationsClient.DEFAULT_MTLS_ENDPOINT - assert StorageBatchOperationsClient._get_api_endpoint(None, None, default_universe, "auto") == default_endpoint - assert StorageBatchOperationsClient._get_api_endpoint(None, None, default_universe, "always") == StorageBatchOperationsClient.DEFAULT_MTLS_ENDPOINT - assert StorageBatchOperationsClient._get_api_endpoint(None, mock_client_cert_source, default_universe, "always") == StorageBatchOperationsClient.DEFAULT_MTLS_ENDPOINT - assert StorageBatchOperationsClient._get_api_endpoint(None, None, mock_universe, "never") == mock_endpoint - assert StorageBatchOperationsClient._get_api_endpoint(None, None, default_universe, "never") == default_endpoint - - with pytest.raises(MutualTLSChannelError) as excinfo: - StorageBatchOperationsClient._get_api_endpoint(None, mock_client_cert_source, mock_universe, "auto") - assert str(excinfo.value) == "mTLS is not supported in any universe other than googleapis.com." - - -def test__get_universe_domain(): - client_universe_domain = "foo.com" - universe_domain_env = "bar.com" - - assert StorageBatchOperationsClient._get_universe_domain(client_universe_domain, universe_domain_env) == client_universe_domain - assert StorageBatchOperationsClient._get_universe_domain(None, universe_domain_env) == universe_domain_env - assert StorageBatchOperationsClient._get_universe_domain(None, None) == StorageBatchOperationsClient._DEFAULT_UNIVERSE + yield - with pytest.raises(ValueError) as excinfo: - StorageBatchOperationsClient._get_universe_domain("", None) - assert str(excinfo.value) == "Universe Domain cannot be an empty string." @pytest.mark.parametrize("error_code,cred_info_json,show_cred_info", [ (401, CRED_INFO_JSON, True), @@ -351,81 +171,6 @@ def test__add_cred_info_for_auth_errors_no_get_cred_info(error_code): client._add_cred_info_for_auth_errors(error) assert error.details == [] -def test__setup_request_id(): - class MockRequest: - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - def __contains__(self, key): - return hasattr(self, key) - - class MockProtoRequest: - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - def HasField(self, key): - return hasattr(self, key) - - # Test with proto3 optional field not in request - request = MockRequest() - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request.request_id) - - # Test with proto3 optional field already in request - request = MockRequest(request_id="already_set") - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert request.request_id == "already_set" - - # Test with non-proto3 optional field empty - request = MockRequest(request_id="") - StorageBatchOperationsClient._setup_request_id(request, "request_id", False) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request.request_id) - - # Test with non-proto3 optional field already set - request = MockRequest(request_id="already_set") - StorageBatchOperationsClient._setup_request_id(request, "request_id", False) - assert request.request_id == "already_set" - - # Test with proto3 optional field not in request (MockProtoRequest) - request = MockProtoRequest() - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request.request_id) - - # Test with proto3 optional field already in request (MockProtoRequest) - request = MockProtoRequest(request_id="already_set") - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert request.request_id == "already_set" - - # Test with ValueError - class MockValueErrorRequest: - def HasField(self, key): - raise ValueError("Mismatched field") - def __contains__(self, key): - return hasattr(self, key) - - request = MockValueErrorRequest() - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request.request_id) - - # Test with dict and proto3 optional field not in request - request = {} - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request["request_id"]) - - # Test with dict and proto3 optional field already in request - request = {"request_id": "already_set"} - StorageBatchOperationsClient._setup_request_id(request, "request_id", True) - assert request["request_id"] == "already_set" - - # Test with dict and non-proto3 optional field empty - request = {"request_id": ""} - StorageBatchOperationsClient._setup_request_id(request, "request_id", False) - assert re.match(r"[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}", request["request_id"]) - - # Test with dict and non-proto3 optional field already set - request = {"request_id": "already_set"} - StorageBatchOperationsClient._setup_request_id(request, "request_id", False) - assert request["request_id"] == "already_set" @pytest.mark.parametrize("client_class,transport_name", [ (StorageBatchOperationsClient, "grpc"), @@ -772,6 +517,7 @@ def test_storage_batch_operations_client_get_mtls_endpoint_and_cert_source(clien for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None) + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data) @@ -819,6 +565,7 @@ def test_storage_batch_operations_client_get_mtls_endpoint_and_cert_source(clien for config_data, expected_cert_source in test_cases: env = os.environ.copy() env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "") + env.pop("CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE", None) with mock.patch.dict(os.environ, env, clear=True): config_filename = "mock_certificate_config.json" config_file_content = json.dumps(config_data)