google-api-core 2.33.0__tar.gz → 2.34.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {google_api_core-2.33.0/google_api_core.egg-info → google_api_core-2.34.0}/PKG-INFO +6 -9
- google_api_core-2.34.0/google/api_core/_feature_gating_helpers.py +139 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/_python_package_support.py +2 -2
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/gapic_v1/method.py +72 -11
- google_api_core-2.34.0/google/api_core/gapic_v1/requests.py +100 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/grpc_helpers.py +14 -5
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/rest_helpers.py +68 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/version.py +1 -1
- {google_api_core-2.33.0 → google_api_core-2.34.0/google_api_core.egg-info}/PKG-INFO +6 -9
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google_api_core.egg-info/SOURCES.txt +3 -0
- google_api_core-2.34.0/google_api_core.egg-info/requires.txt +17 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/pyproject.toml +5 -8
- google_api_core-2.34.0/tests/conftest.py +31 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/gapic/test_method.py +98 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/gapic/test_requests.py +25 -0
- google_api_core-2.34.0/tests/unit/test_feature_gating_helpers.py +224 -0
- google_api_core-2.34.0/tests/unit/test_rest_helpers.py +278 -0
- google_api_core-2.33.0/google/api_core/gapic_v1/requests.py +0 -72
- google_api_core-2.33.0/google_api_core.egg-info/requires.txt +0 -24
- google_api_core-2.33.0/tests/unit/test_rest_helpers.py +0 -94
- {google_api_core-2.33.0 → google_api_core-2.34.0}/LICENSE +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/MANIFEST.in +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/README.rst +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/_python_version_support.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/_rest_streaming_base.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/bidi.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/bidi_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/bidi_base.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/client_info.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/client_logging.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/client_options.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/datetime_helpers.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/exceptions.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/extended_operation.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/future/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/future/_helpers.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/future/async_future.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/future/base.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/future/polling.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/gapic_v1/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/gapic_v1/client_info.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/gapic_v1/config.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/gapic_v1/config_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/gapic_v1/method_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/gapic_v1/routing_header.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/general_helpers.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/grpc_helpers_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/iam.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operation.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operation_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/abstract_operations_base_client.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/abstract_operations_client.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/operations_async_client.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/operations_client.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/operations_client_config.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/operations_rest_client_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/pagers.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/pagers_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/pagers_base.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/transports/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/transports/base.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/transports/rest.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/operations_v1/transports/rest_asyncio.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/page_iterator.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/page_iterator_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/path_template.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/protobuf_helpers.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/py.typed +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/rest_streaming.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/rest_streaming_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/retry/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/retry/retry_base.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/retry/retry_streaming.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/retry/retry_streaming_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/retry/retry_unary.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/retry/retry_unary_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/retry_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/timeout.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/universe.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/version_header.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google_api_core.egg-info/dependency_links.txt +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/google_api_core.egg-info/top_level.txt +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/setup.cfg +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/setup.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/future/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/future/test_async_future.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/gapic/test_config_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/gapic/test_method_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/operations_v1/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/operations_v1/test_operations_async_client.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/retry/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/retry/test_retry_streaming_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/retry/test_retry_unary_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/test_bidi_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/test_grpc_helpers_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/test_operation_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/test_page_iterator_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/asyncio/test_rest_streaming_async.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/helpers.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/future/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/future/test__helpers.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/future/test_polling.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/gapic/test_client_info.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/gapic/test_config.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/gapic/test_routing_header.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/operations_v1/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/operations_v1/test_operations_client.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/operations_v1/test_operations_rest_client.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/retry/__init__.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/retry/test_retry_base.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/retry/test_retry_imports.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/retry/test_retry_streaming.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/retry/test_retry_unary.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_bidi.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_client_info.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_client_logging.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_client_options.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_datetime_helpers.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_exceptions.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_extended_operation.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_grpc_helpers.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_iam.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_operation.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_packaging.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_page_iterator.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_path_template.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_protobuf_helpers.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_python_package_support.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_python_version_support.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_rest_streaming.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_timeout.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_universe.py +0 -0
- {google_api_core-2.33.0 → google_api_core-2.34.0}/tests/unit/test_version_header.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-api-core
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.34.0
|
|
4
4
|
Summary: Google API client core library
|
|
5
5
|
Author-email: Google LLC <googleapis-packages@google.com>
|
|
6
6
|
License: Apache 2.0
|
|
@@ -22,21 +22,18 @@ Classifier: Topic :: Internet
|
|
|
22
22
|
Requires-Python: >=3.10
|
|
23
23
|
Description-Content-Type: text/x-rst
|
|
24
24
|
License-File: LICENSE
|
|
25
|
-
Requires-Dist: googleapis-common-protos<2.0.0,>=1.
|
|
26
|
-
Requires-Dist: protobuf<8.0.0,>=
|
|
27
|
-
Requires-Dist: proto-plus<2.0.0,>=1.
|
|
28
|
-
Requires-Dist: proto-plus<2.0.0,>=1.25.0; python_version >= "3.13"
|
|
25
|
+
Requires-Dist: googleapis-common-protos<2.0.0,>=1.69.2
|
|
26
|
+
Requires-Dist: protobuf<8.0.0,>=6.33.5
|
|
27
|
+
Requires-Dist: proto-plus<2.0.0,>=1.26.1
|
|
29
28
|
Requires-Dist: google-auth<3.0.0,>=2.14.1
|
|
30
29
|
Requires-Dist: requests<3.0.0,>=2.33.0
|
|
31
30
|
Provides-Extra: async-rest
|
|
32
31
|
Requires-Dist: google-auth[aiohttp]<3.0.0,>=2.14.1; extra == "async-rest"
|
|
33
32
|
Requires-Dist: aiohttp>=3.13.4; extra == "async-rest"
|
|
34
33
|
Provides-Extra: grpc
|
|
35
|
-
Requires-Dist: grpcio<2.0.0,>=1.
|
|
36
|
-
Requires-Dist: grpcio<2.0.0,>=1.49.1; python_version >= "3.11" and extra == "grpc"
|
|
34
|
+
Requires-Dist: grpcio<2.0.0,>=1.59.0; extra == "grpc"
|
|
37
35
|
Requires-Dist: grpcio<2.0.0,>=1.75.1; python_version >= "3.14" and extra == "grpc"
|
|
38
|
-
Requires-Dist: grpcio-status<2.0.0,>=1.
|
|
39
|
-
Requires-Dist: grpcio-status<2.0.0,>=1.49.1; python_version >= "3.11" and extra == "grpc"
|
|
36
|
+
Requires-Dist: grpcio-status<2.0.0,>=1.59.0; extra == "grpc"
|
|
40
37
|
Requires-Dist: grpcio-status<2.0.0,>=1.75.1; python_version >= "3.14" and extra == "grpc"
|
|
41
38
|
Dynamic: license-file
|
|
42
39
|
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright 2026 Google LLC
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
"""Observability environment variable and client options resolution helpers."""
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
import warnings
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
# We import ClientOptions for type hinting
|
|
24
|
+
from google.api_core.client_options import ClientOptions
|
|
25
|
+
|
|
26
|
+
# Allowed truthy and falsy patterns for environment variables
|
|
27
|
+
_TRUTHY_VALUES = ("y", "yes", "t", "true", "on", "1")
|
|
28
|
+
_FALSY_VALUES = ("n", "no", "f", "false", "off", "0")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class FeatureGatingError(ValueError):
|
|
32
|
+
"""Raised when feature gating resolution fails or is misconfigured."""
|
|
33
|
+
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _strtobool(val: str) -> bool | None:
|
|
38
|
+
"""Convert a string representation of truth to a boolean."""
|
|
39
|
+
clean_val = val.lower().strip()
|
|
40
|
+
if not clean_val:
|
|
41
|
+
return None
|
|
42
|
+
if clean_val in _TRUTHY_VALUES:
|
|
43
|
+
return True
|
|
44
|
+
if clean_val in _FALSY_VALUES:
|
|
45
|
+
return False
|
|
46
|
+
raise ValueError(f"Invalid truth value: {val!r}")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _get_env_bool(name: str) -> bool | None:
|
|
50
|
+
"""Retrieve the boolean value of an environment variable."""
|
|
51
|
+
val = os.getenv(name)
|
|
52
|
+
if val is None:
|
|
53
|
+
return None
|
|
54
|
+
try:
|
|
55
|
+
return _strtobool(val)
|
|
56
|
+
except ValueError as e:
|
|
57
|
+
warnings.warn(f"Ignored invalid value for {name}: {e}", RuntimeWarning)
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _has_feature_key(
|
|
62
|
+
*, configuration: ClientOptions | dict[str, Any] | None, feature_key: str
|
|
63
|
+
) -> bool:
|
|
64
|
+
"""Checks if a specific feature key is present and not None in configuration."""
|
|
65
|
+
if configuration is None:
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
if feature_key.startswith("__"):
|
|
69
|
+
return False
|
|
70
|
+
|
|
71
|
+
if isinstance(configuration, dict):
|
|
72
|
+
return configuration.get(feature_key) is not None
|
|
73
|
+
|
|
74
|
+
return getattr(configuration, feature_key, None) is not None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def resolve_feature_flags(
|
|
78
|
+
*,
|
|
79
|
+
env_var: str,
|
|
80
|
+
feature_key: str,
|
|
81
|
+
configuration: ClientOptions | dict[str, Any] | None = None,
|
|
82
|
+
) -> bool:
|
|
83
|
+
"""Determines if a feature is enabled based on environment variables and configuration.
|
|
84
|
+
|
|
85
|
+
Behavior depends on whether the `env_var` name contains "EXPERIMENTAL":
|
|
86
|
+
|
|
87
|
+
- **Experimental Path** (env_var contains "EXPERIMENTAL"):
|
|
88
|
+
Strict control. Requires the environment variable to be explicitly 'true'.
|
|
89
|
+
If a programmatic feature key is passed but the environment variable is not 'true',
|
|
90
|
+
raises FeatureGatingError (Fail Fast).
|
|
91
|
+
|
|
92
|
+
- **GA Path** (env_var does not contain "EXPERIMENTAL"):
|
|
93
|
+
Standard precedence. Enabled if a programmatic feature key is passed,
|
|
94
|
+
otherwise falls back to the environment variable value.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
env_var: The name of the environment variable controlling this feature.
|
|
98
|
+
feature_key: The key in configuration/attributes for the programmatic configuration.
|
|
99
|
+
configuration: Optional. A dictionary or object containing client configuration.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
bool: True if the feature is resolved to enabled, False otherwise.
|
|
103
|
+
|
|
104
|
+
Raises:
|
|
105
|
+
FeatureGatingError: If a feature key is provided for an experimental feature without enabling the experimental environment variable.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
# Check for programmatic feature configuration
|
|
109
|
+
has_feature_key = _has_feature_key(
|
|
110
|
+
configuration=configuration, feature_key=feature_key
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Read environment variable
|
|
114
|
+
env_var_setting = _get_env_bool(env_var)
|
|
115
|
+
|
|
116
|
+
# EXPERIMENTAL PATH:
|
|
117
|
+
# Resolution Hierarchy:
|
|
118
|
+
# 1. EXPERIMENTAL Environment Variable
|
|
119
|
+
# 2. Fail Fast if Feature Key present but EXPERIMENTAL Environment Variable is not enabled
|
|
120
|
+
if "EXPERIMENTAL" in env_var:
|
|
121
|
+
# Fail Fast if feature key present but experimental environment variable is not enabled
|
|
122
|
+
if env_var_setting is not True and has_feature_key:
|
|
123
|
+
raise FeatureGatingError(
|
|
124
|
+
f"Experimental feature requires {env_var} to be set to 'true' to use programmatic configuration."
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
return bool(env_var_setting)
|
|
128
|
+
|
|
129
|
+
# GENERAL AVAILABILITY PATH:
|
|
130
|
+
# Resolution Hierarchy:
|
|
131
|
+
# 1. Programmatic Configuration (Feature Key)
|
|
132
|
+
# 2. Environment Variable
|
|
133
|
+
|
|
134
|
+
# Check Programmatic Configuration
|
|
135
|
+
if has_feature_key:
|
|
136
|
+
return True
|
|
137
|
+
|
|
138
|
+
# Check Environment Variable
|
|
139
|
+
return bool(env_var_setting)
|
{google_api_core-2.33.0 → google_api_core-2.34.0}/google/api_core/_python_package_support.py
RENAMED
|
@@ -35,7 +35,7 @@ DependencyConstraint = namedtuple(
|
|
|
35
35
|
_PACKAGE_DEPENDENCY_WARNINGS = [
|
|
36
36
|
DependencyConstraint(
|
|
37
37
|
"google.protobuf",
|
|
38
|
-
minimum_fully_supported_version="
|
|
38
|
+
minimum_fully_supported_version="6.33.5",
|
|
39
39
|
recommended_version="6.x",
|
|
40
40
|
)
|
|
41
41
|
]
|
|
@@ -50,7 +50,7 @@ UNKNOWN_VERSION_STRING = "--"
|
|
|
50
50
|
def parse_version_to_tuple(version_string: str) -> ParsedVersion:
|
|
51
51
|
"""Safely converts a semantic version string to a comparable tuple of integers.
|
|
52
52
|
|
|
53
|
-
Example: "
|
|
53
|
+
Example: "6.33.5" -> (6, 33, 5)
|
|
54
54
|
Ignores non-numeric parts and handles common version formats.
|
|
55
55
|
|
|
56
56
|
Args:
|
|
@@ -20,6 +20,7 @@ compression, pagination, and long-running operations to gRPC methods.
|
|
|
20
20
|
|
|
21
21
|
import enum
|
|
22
22
|
import functools
|
|
23
|
+
from typing import List, Tuple
|
|
23
24
|
|
|
24
25
|
from google.api_core import grpc_helpers
|
|
25
26
|
from google.api_core.gapic_v1 import client_info
|
|
@@ -57,6 +58,52 @@ def _apply_decorators(func, decorators):
|
|
|
57
58
|
return func
|
|
58
59
|
|
|
59
60
|
|
|
61
|
+
def _deduplicate_metadata_tokens(*headers: str | None) -> str:
|
|
62
|
+
"""
|
|
63
|
+
Given one or more metadata payload strings, create a combined
|
|
64
|
+
string with deduplicated tokens, while preserving token order.
|
|
65
|
+
|
|
66
|
+
Inputs are expected to contain a set of metadata tokens separated by spaces
|
|
67
|
+
Example: `gl-python/3.14.0 grpc/1.76.0 gax/2.29.0 gapic/3.8.0 pb/6.33.4`
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
*headers: one or more metadata payload strings
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
a single combined payload string
|
|
74
|
+
"""
|
|
75
|
+
# Split all non-empty headers into individual tokens
|
|
76
|
+
token_list = " ".join(filter(None, headers)).split()
|
|
77
|
+
# Deduplicate while preserving order
|
|
78
|
+
return " ".join(dict.fromkeys(token_list))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _extract_metrics_header(metadata) -> Tuple[str, List[Tuple[str, str]]]:
|
|
82
|
+
"""Extract x-google-api-client header from metadata list.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
metadata (Sequence[Tuple[str, str]]): The metadata to extract from.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
A tuple containing:
|
|
89
|
+
- a string representing the header value.
|
|
90
|
+
- A sequence of remaining metadata tuples.
|
|
91
|
+
"""
|
|
92
|
+
if not metadata:
|
|
93
|
+
return "", []
|
|
94
|
+
|
|
95
|
+
key_to_find = client_info.METRICS_METADATA_KEY
|
|
96
|
+
|
|
97
|
+
metric_str = _deduplicate_metadata_tokens(
|
|
98
|
+
" ".join([v for k, v in metadata if k == key_to_find])
|
|
99
|
+
)
|
|
100
|
+
if not metric_str:
|
|
101
|
+
return "", list(metadata)
|
|
102
|
+
|
|
103
|
+
arbitrary_metadata = [item for item in metadata if item[0] != key_to_find]
|
|
104
|
+
return metric_str, arbitrary_metadata
|
|
105
|
+
|
|
106
|
+
|
|
60
107
|
class _GapicCallable(object):
|
|
61
108
|
"""Callable that applies retry, timeout, and metadata logic.
|
|
62
109
|
|
|
@@ -90,7 +137,16 @@ class _GapicCallable(object):
|
|
|
90
137
|
self._retry = retry
|
|
91
138
|
self._timeout = timeout
|
|
92
139
|
self._compression = compression
|
|
93
|
-
|
|
140
|
+
# Pre-extract the x-goog-api-client header from the initialized metadata.
|
|
141
|
+
self._x_goog_api_client, remaining = _extract_metrics_header(metadata)
|
|
142
|
+
self._static_metadata = tuple(remaining)
|
|
143
|
+
if self._x_goog_api_client:
|
|
144
|
+
self._default_metadata = (
|
|
145
|
+
(client_info.METRICS_METADATA_KEY, self._x_goog_api_client),
|
|
146
|
+
*self._static_metadata,
|
|
147
|
+
)
|
|
148
|
+
else:
|
|
149
|
+
self._default_metadata = self._static_metadata
|
|
94
150
|
|
|
95
151
|
def __call__(
|
|
96
152
|
self, *args, timeout=DEFAULT, retry=DEFAULT, compression=DEFAULT, **kwargs
|
|
@@ -112,16 +168,21 @@ class _GapicCallable(object):
|
|
|
112
168
|
# Apply all applicable decorators.
|
|
113
169
|
wrapped_func = _apply_decorators(self._target, [retry, timeout])
|
|
114
170
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
171
|
+
if user_metadata := kwargs.get("metadata"):
|
|
172
|
+
# Add the user agent metadata to the call.
|
|
173
|
+
final_metadata = list(self._static_metadata)
|
|
174
|
+
user_x_goog, remaining = _extract_metrics_header(user_metadata)
|
|
175
|
+
|
|
176
|
+
merged_header = _deduplicate_metadata_tokens(
|
|
177
|
+
self._x_goog_api_client, user_x_goog
|
|
178
|
+
)
|
|
179
|
+
if merged_header:
|
|
180
|
+
final_metadata.append((client_info.METRICS_METADATA_KEY, merged_header))
|
|
181
|
+
final_metadata.extend(remaining)
|
|
182
|
+
kwargs["metadata"] = final_metadata
|
|
183
|
+
elif self._default_metadata:
|
|
184
|
+
kwargs["metadata"] = self._default_metadata
|
|
185
|
+
|
|
125
186
|
if self._compression is not None:
|
|
126
187
|
kwargs["compression"] = compression
|
|
127
188
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright 2026 Google LLC
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
"""Helpers for preparing and structuring API requests.
|
|
18
|
+
|
|
19
|
+
This module provides utilities to preprocess request parameters and objects
|
|
20
|
+
before invoking API methods, such as automatically generating request IDs
|
|
21
|
+
if they are not already set.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import uuid
|
|
25
|
+
from typing import TYPE_CHECKING, Union
|
|
26
|
+
|
|
27
|
+
import google.protobuf.message
|
|
28
|
+
|
|
29
|
+
if TYPE_CHECKING: # pragma: NO COVER
|
|
30
|
+
import proto # type: ignore[import-untyped]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def setup_request_id(
|
|
34
|
+
request: Union[google.protobuf.message.Message, "proto.Message", dict, None],
|
|
35
|
+
field_name: str,
|
|
36
|
+
is_proto3_optional: bool,
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Populate a UUID4 field in the request if it is not already set.
|
|
39
|
+
|
|
40
|
+
This helper is used to ensure request idempotency by automatically
|
|
41
|
+
generating a unique identifier (such as `request_id`) for requests
|
|
42
|
+
that support it. If a request is retried, the same identifier can be
|
|
43
|
+
sent on subsequent retries, allowing the server to recognize the retried
|
|
44
|
+
request and prevent duplicate processing (e.g., creating duplicate
|
|
45
|
+
resources).
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
request (Union[google.protobuf.message.Message, proto.Message, dict, None]): The
|
|
49
|
+
request object or dictionary.
|
|
50
|
+
field_name (str): The name of the field to populate (e.g., "request_id").
|
|
51
|
+
is_proto3_optional (bool): Whether the field supports explicit presence
|
|
52
|
+
(defined with `optional` in proto3 syntax). When True, empty strings ("")
|
|
53
|
+
are preserved as explicit user input per AIP-4235, and UUID auto-population
|
|
54
|
+
occurs only if the field is unset. When False, any empty or falsy value is
|
|
55
|
+
populated with a UUID.
|
|
56
|
+
"""
|
|
57
|
+
if request is None:
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
# Evaluate whether the field is considered "unset" and needs auto-population.
|
|
61
|
+
#
|
|
62
|
+
# According to AIP-4235, optional request ID fields must be populated
|
|
63
|
+
# if and only if they have explicit presence (`is_proto3_optional=True`)
|
|
64
|
+
# and were not set by the user (i.e. unset). Explicitly provided empty
|
|
65
|
+
# strings ('') must be preserved when `is_proto3_optional=True`.
|
|
66
|
+
should_populate = False
|
|
67
|
+
if isinstance(request, dict):
|
|
68
|
+
if is_proto3_optional:
|
|
69
|
+
# Case 1a: Dictionary request with explicit presence (`is_proto3_optional=True`).
|
|
70
|
+
# Per AIP-4235, auto-populate only if the key is completely missing from
|
|
71
|
+
# the dictionary or its value is explicitly set to None.
|
|
72
|
+
# An explicit empty string ('') must NOT be overwritten.
|
|
73
|
+
should_populate = field_name not in request or request[field_name] is None
|
|
74
|
+
else:
|
|
75
|
+
# Case 1b: Dictionary request without explicit presence (`is_proto3_optional=False`).
|
|
76
|
+
# Auto-populate if the key is missing, None, or falsy (e.g., empty string '').
|
|
77
|
+
should_populate = not request.get(field_name)
|
|
78
|
+
else:
|
|
79
|
+
if is_proto3_optional:
|
|
80
|
+
# Case 2a: Proto request with explicit presence (`is_proto3_optional=True`)
|
|
81
|
+
# (proto-plus wrapper or pure protobuf message).
|
|
82
|
+
# Extract the protobuf from proto-plus if wrapped.
|
|
83
|
+
pure_pb: google.protobuf.message.Message = getattr(request, "_pb", request)
|
|
84
|
+
try:
|
|
85
|
+
should_populate = not pure_pb.HasField(field_name)
|
|
86
|
+
except (AttributeError, ValueError):
|
|
87
|
+
# Fall back if `HasField` fails or is unsupported.
|
|
88
|
+
should_populate = getattr(pure_pb, field_name, None) is None
|
|
89
|
+
else:
|
|
90
|
+
# Case 2b: Proto request without explicit presence (`is_proto3_optional=False`).
|
|
91
|
+
# Auto-populate if the field value is falsy (None or empty string '').
|
|
92
|
+
should_populate = not bool(getattr(request, field_name, False))
|
|
93
|
+
|
|
94
|
+
# If the field was found to be empty, set random id
|
|
95
|
+
if should_populate:
|
|
96
|
+
generated_id = str(uuid.uuid4())
|
|
97
|
+
if isinstance(request, dict):
|
|
98
|
+
request[field_name] = generated_id
|
|
99
|
+
else:
|
|
100
|
+
setattr(request, field_name, generated_id)
|
|
@@ -254,11 +254,20 @@ def _create_composite_credentials(
|
|
|
254
254
|
request = google.auth.transport.requests.Request()
|
|
255
255
|
|
|
256
256
|
# Create the metadata plugin for inserting the authorization header.
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
257
|
+
try:
|
|
258
|
+
metadata_plugin = google.auth.transport.grpc.AuthMetadataPlugin(
|
|
259
|
+
credentials,
|
|
260
|
+
request,
|
|
261
|
+
default_host=default_host,
|
|
262
|
+
suppress_metrics_header=True,
|
|
263
|
+
)
|
|
264
|
+
except TypeError:
|
|
265
|
+
# Support older versions of google-auth that do not accept suppress_metrics_header
|
|
266
|
+
metadata_plugin = google.auth.transport.grpc.AuthMetadataPlugin(
|
|
267
|
+
credentials,
|
|
268
|
+
request,
|
|
269
|
+
default_host=default_host,
|
|
270
|
+
)
|
|
262
271
|
|
|
263
272
|
# Create a set of grpc.CallCredentials using the metadata plugin.
|
|
264
273
|
google_auth_credentials = grpc.metadata_call_credentials(metadata_plugin)
|
|
@@ -15,7 +15,14 @@
|
|
|
15
15
|
"""Helpers for rest transports."""
|
|
16
16
|
|
|
17
17
|
import functools
|
|
18
|
+
import json
|
|
18
19
|
import operator
|
|
20
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
21
|
+
|
|
22
|
+
from google.api_core import path_template
|
|
23
|
+
from google.protobuf import json_format
|
|
24
|
+
|
|
25
|
+
__all__ = ["flatten_query_params", "transcode", "transcode_request"]
|
|
19
26
|
|
|
20
27
|
|
|
21
28
|
def flatten_query_params(obj, strict=False):
|
|
@@ -107,3 +114,64 @@ def _canonicalize(obj, strict=False):
|
|
|
107
114
|
value = value.lower()
|
|
108
115
|
return value
|
|
109
116
|
return obj
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def transcode_request(
|
|
120
|
+
http_options: List[Dict[str, str]],
|
|
121
|
+
request: Any,
|
|
122
|
+
required_fields_default_values: Optional[Dict[str, Any]] = None,
|
|
123
|
+
rest_numeric_enums: bool = False,
|
|
124
|
+
) -> Tuple[Dict[str, Any], Optional[str], Dict[str, Any]]:
|
|
125
|
+
"""Transcodes a request into HTTP method, URI, body, and query parameters.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
http_options (List[Dict[str, str]]): List of HTTP transcoding rules.
|
|
129
|
+
request (Any): The protobuf or proto-plus request message.
|
|
130
|
+
required_fields_default_values (Optional[Dict[str, Any]]): Dictionary
|
|
131
|
+
of required fields default values to merge into query parameters if missing.
|
|
132
|
+
rest_numeric_enums (bool): Whether to encode enums as integers.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Tuple[Dict[str, Any], Optional[str], Dict[str, Any]]: A tuple containing:
|
|
136
|
+
- The raw transcoded request dictionary (containing keys like 'uri', 'method').
|
|
137
|
+
- The serialized request body JSON string, or None if no body.
|
|
138
|
+
- The query parameters dictionary.
|
|
139
|
+
"""
|
|
140
|
+
if request is None:
|
|
141
|
+
raise TypeError("request cannot be None")
|
|
142
|
+
|
|
143
|
+
# Convert proto-plus message to its underlying protobuf message if needed
|
|
144
|
+
pb_request = getattr(request, "_pb", request)
|
|
145
|
+
|
|
146
|
+
transcoded_request = path_template.transcode(http_options, pb_request)
|
|
147
|
+
|
|
148
|
+
body_json = None
|
|
149
|
+
if transcoded_request.get("body") is not None:
|
|
150
|
+
body_json = json_format.MessageToJson(
|
|
151
|
+
transcoded_request["body"],
|
|
152
|
+
use_integers_for_enums=rest_numeric_enums,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
query_params_json = {}
|
|
156
|
+
if transcoded_request.get("query_params") is not None:
|
|
157
|
+
query_params_json = json.loads(
|
|
158
|
+
json_format.MessageToJson(
|
|
159
|
+
transcoded_request["query_params"],
|
|
160
|
+
use_integers_for_enums=rest_numeric_enums,
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# If required_fields_default_values is provided, we merge default values for missing
|
|
165
|
+
# required fields into the query parameters.
|
|
166
|
+
if required_fields_default_values:
|
|
167
|
+
for k, v in required_fields_default_values.items():
|
|
168
|
+
if k not in query_params_json:
|
|
169
|
+
query_params_json[k] = v
|
|
170
|
+
|
|
171
|
+
if rest_numeric_enums:
|
|
172
|
+
query_params_json["$alt"] = "json;enum-encoding=int"
|
|
173
|
+
|
|
174
|
+
return transcoded_request, body_json, query_params_json
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
transcode = transcode_request
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-api-core
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.34.0
|
|
4
4
|
Summary: Google API client core library
|
|
5
5
|
Author-email: Google LLC <googleapis-packages@google.com>
|
|
6
6
|
License: Apache 2.0
|
|
@@ -22,21 +22,18 @@ Classifier: Topic :: Internet
|
|
|
22
22
|
Requires-Python: >=3.10
|
|
23
23
|
Description-Content-Type: text/x-rst
|
|
24
24
|
License-File: LICENSE
|
|
25
|
-
Requires-Dist: googleapis-common-protos<2.0.0,>=1.
|
|
26
|
-
Requires-Dist: protobuf<8.0.0,>=
|
|
27
|
-
Requires-Dist: proto-plus<2.0.0,>=1.
|
|
28
|
-
Requires-Dist: proto-plus<2.0.0,>=1.25.0; python_version >= "3.13"
|
|
25
|
+
Requires-Dist: googleapis-common-protos<2.0.0,>=1.69.2
|
|
26
|
+
Requires-Dist: protobuf<8.0.0,>=6.33.5
|
|
27
|
+
Requires-Dist: proto-plus<2.0.0,>=1.26.1
|
|
29
28
|
Requires-Dist: google-auth<3.0.0,>=2.14.1
|
|
30
29
|
Requires-Dist: requests<3.0.0,>=2.33.0
|
|
31
30
|
Provides-Extra: async-rest
|
|
32
31
|
Requires-Dist: google-auth[aiohttp]<3.0.0,>=2.14.1; extra == "async-rest"
|
|
33
32
|
Requires-Dist: aiohttp>=3.13.4; extra == "async-rest"
|
|
34
33
|
Provides-Extra: grpc
|
|
35
|
-
Requires-Dist: grpcio<2.0.0,>=1.
|
|
36
|
-
Requires-Dist: grpcio<2.0.0,>=1.49.1; python_version >= "3.11" and extra == "grpc"
|
|
34
|
+
Requires-Dist: grpcio<2.0.0,>=1.59.0; extra == "grpc"
|
|
37
35
|
Requires-Dist: grpcio<2.0.0,>=1.75.1; python_version >= "3.14" and extra == "grpc"
|
|
38
|
-
Requires-Dist: grpcio-status<2.0.0,>=1.
|
|
39
|
-
Requires-Dist: grpcio-status<2.0.0,>=1.49.1; python_version >= "3.11" and extra == "grpc"
|
|
36
|
+
Requires-Dist: grpcio-status<2.0.0,>=1.59.0; extra == "grpc"
|
|
40
37
|
Requires-Dist: grpcio-status<2.0.0,>=1.75.1; python_version >= "3.14" and extra == "grpc"
|
|
41
38
|
Dynamic: license-file
|
|
42
39
|
|
|
@@ -5,6 +5,7 @@ pyproject.toml
|
|
|
5
5
|
setup.cfg
|
|
6
6
|
setup.py
|
|
7
7
|
google/api_core/__init__.py
|
|
8
|
+
google/api_core/_feature_gating_helpers.py
|
|
8
9
|
google/api_core/_python_package_support.py
|
|
9
10
|
google/api_core/_python_version_support.py
|
|
10
11
|
google/api_core/_rest_streaming_base.py
|
|
@@ -75,6 +76,7 @@ google_api_core.egg-info/dependency_links.txt
|
|
|
75
76
|
google_api_core.egg-info/requires.txt
|
|
76
77
|
google_api_core.egg-info/top_level.txt
|
|
77
78
|
tests/__init__.py
|
|
79
|
+
tests/conftest.py
|
|
78
80
|
tests/helpers.py
|
|
79
81
|
tests/asyncio/__init__.py
|
|
80
82
|
tests/asyncio/test_bidi_async.py
|
|
@@ -99,6 +101,7 @@ tests/unit/test_client_options.py
|
|
|
99
101
|
tests/unit/test_datetime_helpers.py
|
|
100
102
|
tests/unit/test_exceptions.py
|
|
101
103
|
tests/unit/test_extended_operation.py
|
|
104
|
+
tests/unit/test_feature_gating_helpers.py
|
|
102
105
|
tests/unit/test_grpc_helpers.py
|
|
103
106
|
tests/unit/test_iam.py
|
|
104
107
|
tests/unit/test_operation.py
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
googleapis-common-protos<2.0.0,>=1.69.2
|
|
2
|
+
protobuf<8.0.0,>=6.33.5
|
|
3
|
+
proto-plus<2.0.0,>=1.26.1
|
|
4
|
+
google-auth<3.0.0,>=2.14.1
|
|
5
|
+
requests<3.0.0,>=2.33.0
|
|
6
|
+
|
|
7
|
+
[async_rest]
|
|
8
|
+
google-auth[aiohttp]<3.0.0,>=2.14.1
|
|
9
|
+
aiohttp>=3.13.4
|
|
10
|
+
|
|
11
|
+
[grpc]
|
|
12
|
+
grpcio<2.0.0,>=1.59.0
|
|
13
|
+
grpcio-status<2.0.0,>=1.59.0
|
|
14
|
+
|
|
15
|
+
[grpc:python_version >= "3.14"]
|
|
16
|
+
grpcio<2.0.0,>=1.75.1
|
|
17
|
+
grpcio-status<2.0.0,>=1.75.1
|
|
@@ -43,10 +43,9 @@ classifiers = [
|
|
|
43
43
|
"Topic :: Internet",
|
|
44
44
|
]
|
|
45
45
|
dependencies = [
|
|
46
|
-
"googleapis-common-protos >= 1.
|
|
47
|
-
"protobuf >=
|
|
48
|
-
"proto-plus >= 1.
|
|
49
|
-
"proto-plus >= 1.25.0, < 2.0.0; python_version >= '3.13'",
|
|
46
|
+
"googleapis-common-protos >= 1.69.2, < 2.0.0",
|
|
47
|
+
"protobuf >= 6.33.5, < 8.0.0",
|
|
48
|
+
"proto-plus >= 1.26.1, < 2.0.0",
|
|
50
49
|
"google-auth >= 2.14.1, < 3.0.0",
|
|
51
50
|
"requests >= 2.33.0, < 3.0.0",
|
|
52
51
|
]
|
|
@@ -60,11 +59,9 @@ Repository = "https://github.com/googleapis/google-cloud-python"
|
|
|
60
59
|
[project.optional-dependencies]
|
|
61
60
|
async_rest = ["google-auth[aiohttp] >= 2.14.1, < 3.0.0", "aiohttp >= 3.13.4"]
|
|
62
61
|
grpc = [
|
|
63
|
-
"grpcio >= 1.
|
|
64
|
-
"grpcio >= 1.49.1, < 2.0.0; python_version >= '3.11'",
|
|
62
|
+
"grpcio >= 1.59.0, < 2.0.0",
|
|
65
63
|
"grpcio >= 1.75.1, < 2.0.0; python_version >= '3.14'",
|
|
66
|
-
"grpcio-status >= 1.
|
|
67
|
-
"grpcio-status >= 1.49.1, < 2.0.0; python_version >= '3.11'",
|
|
64
|
+
"grpcio-status >= 1.59.0, < 2.0.0",
|
|
68
65
|
"grpcio-status >= 1.75.1, < 2.0.0; python_version >= '3.14'",
|
|
69
66
|
]
|
|
70
67
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Copyright 2026 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
from unittest import mock
|
|
17
|
+
|
|
18
|
+
import pytest
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.fixture(scope="session", autouse=True)
|
|
22
|
+
def mock_mtls_env():
|
|
23
|
+
"""Autouse session-scoped fixture to isolate unit tests from workstation mTLS environments."""
|
|
24
|
+
with mock.patch.dict(
|
|
25
|
+
os.environ,
|
|
26
|
+
{
|
|
27
|
+
"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false",
|
|
28
|
+
"CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE": "false",
|
|
29
|
+
},
|
|
30
|
+
):
|
|
31
|
+
yield
|