google-api-core 2.28.0__tar.gz → 2.29.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.28.0/google_api_core.egg-info → google_api_core-2.29.0}/PKG-INFO +2 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/__init__.py +1 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/_python_package_support.py +45 -20
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/_python_version_support.py +17 -8
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/bidi.py +3 -3
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/bidi_async.py +3 -3
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/grpc_helpers_async.py +1 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operation.py +1 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/abstract_operations_base_client.py +14 -8
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/pagers.py +1 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/pagers_async.py +1 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/pagers_base.py +1 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/transports/base.py +7 -4
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/version.py +1 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0/google_api_core.egg-info}/PKG-INFO +2 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google_api_core.egg-info/requires.txt +3 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/pyproject.toml +6 -1
- google_api_core-2.29.0/setup.cfg +4 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/gapic/test_method_async.py +1 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/test_bidi_async.py +15 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/test_grpc_helpers_async.py +19 -14
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/test_rest_streaming_async.py +0 -2
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/helpers.py +11 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/gapic/test_method.py +21 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/gapic/test_routing_header.py +2 -2
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/operations_v1/test_operations_rest_client.py +52 -20
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_bidi.py +10 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_client_logging.py +0 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_client_options.py +19 -19
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_grpc_helpers.py +17 -12
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_page_iterator.py +0 -1
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_python_package_support.py +28 -35
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_python_version_support.py +12 -8
- google_api_core-2.28.0/setup.cfg +0 -13
- {google_api_core-2.28.0 → google_api_core-2.29.0}/LICENSE +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/MANIFEST.in +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/README.rst +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/_rest_streaming_base.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/bidi_base.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/client_info.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/client_logging.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/client_options.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/datetime_helpers.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/exceptions.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/extended_operation.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/future/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/future/_helpers.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/future/async_future.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/future/base.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/future/polling.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/gapic_v1/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/gapic_v1/client_info.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/gapic_v1/config.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/gapic_v1/config_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/gapic_v1/method.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/gapic_v1/method_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/gapic_v1/routing_header.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/general_helpers.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/grpc_helpers.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/iam.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operation_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/abstract_operations_client.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/operations_async_client.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/operations_client.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/operations_client_config.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/operations_rest_client_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/transports/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/transports/rest.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/transports/rest_asyncio.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/page_iterator.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/page_iterator_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/path_template.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/protobuf_helpers.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/py.typed +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/rest_helpers.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/rest_streaming.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/rest_streaming_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/retry/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/retry/retry_base.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/retry/retry_streaming.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/retry/retry_streaming_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/retry/retry_unary.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/retry/retry_unary_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/retry_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/timeout.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/universe.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/version_header.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google_api_core.egg-info/SOURCES.txt +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google_api_core.egg-info/dependency_links.txt +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/google_api_core.egg-info/top_level.txt +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/setup.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/future/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/future/test_async_future.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/gapic/test_config_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/operations_v1/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/operations_v1/test_operations_async_client.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/retry/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/retry/test_retry_streaming_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/retry/test_retry_unary_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/test_operation_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/test_page_iterator_async.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/future/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/future/test__helpers.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/future/test_polling.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/gapic/test_client_info.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/gapic/test_config.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/operations_v1/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/operations_v1/test_operations_client.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/retry/__init__.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/retry/test_retry_base.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/retry/test_retry_imports.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/retry/test_retry_streaming.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/retry/test_retry_unary.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_client_info.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_datetime_helpers.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_exceptions.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_extended_operation.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_iam.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_operation.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_packaging.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_path_template.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_protobuf_helpers.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_rest_helpers.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_rest_streaming.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_timeout.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.0}/tests/unit/test_universe.py +0 -0
- {google_api_core-2.28.0 → google_api_core-2.29.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.29.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
|
|
@@ -30,6 +30,7 @@ Requires-Dist: proto-plus<2.0.0,>=1.22.3
|
|
|
30
30
|
Requires-Dist: proto-plus<2.0.0,>=1.25.0; python_version >= "3.13"
|
|
31
31
|
Requires-Dist: google-auth<3.0.0,>=2.14.1
|
|
32
32
|
Requires-Dist: requests<3.0.0,>=2.18.0
|
|
33
|
+
Requires-Dist: importlib_metadata>=1.4; python_version < "3.8"
|
|
33
34
|
Provides-Extra: async-rest
|
|
34
35
|
Requires-Dist: google-auth[aiohttp]<3.0.0,>=2.35.0; extra == "async-rest"
|
|
35
36
|
Provides-Extra: grpc
|
|
@@ -30,6 +30,7 @@ __version__ = api_core_version.__version__
|
|
|
30
30
|
# expose dependency checks for external callers
|
|
31
31
|
check_python_version = _python_version_support.check_python_version
|
|
32
32
|
check_dependency_versions = _python_package_support.check_dependency_versions
|
|
33
|
+
parse_version_to_tuple = _python_package_support.parse_version_to_tuple
|
|
33
34
|
warn_deprecation_for_versions_less_than = (
|
|
34
35
|
_python_package_support.warn_deprecation_for_versions_less_than
|
|
35
36
|
)
|
{google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/_python_package_support.py
RENAMED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import warnings
|
|
18
18
|
import sys
|
|
19
|
-
from typing import Optional
|
|
19
|
+
from typing import Optional, Tuple
|
|
20
20
|
|
|
21
21
|
from collections import namedtuple
|
|
22
22
|
|
|
@@ -25,7 +25,14 @@ from ._python_version_support import (
|
|
|
25
25
|
_get_distribution_and_import_packages,
|
|
26
26
|
)
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
if sys.version_info >= (3, 8):
|
|
29
|
+
from importlib import metadata
|
|
30
|
+
else:
|
|
31
|
+
# TODO(https://github.com/googleapis/python-api-core/issues/835): Remove
|
|
32
|
+
# this code path once we drop support for Python 3.7
|
|
33
|
+
import importlib_metadata as metadata
|
|
34
|
+
|
|
35
|
+
ParsedVersion = Tuple[int, ...]
|
|
29
36
|
|
|
30
37
|
# Here we list all the packages for which we want to issue warnings
|
|
31
38
|
# about deprecated and unsupported versions.
|
|
@@ -48,42 +55,56 @@ DependencyVersion = namedtuple("DependencyVersion", ["version", "version_string"
|
|
|
48
55
|
UNKNOWN_VERSION_STRING = "--"
|
|
49
56
|
|
|
50
57
|
|
|
58
|
+
def parse_version_to_tuple(version_string: str) -> ParsedVersion:
|
|
59
|
+
"""Safely converts a semantic version string to a comparable tuple of integers.
|
|
60
|
+
|
|
61
|
+
Example: "4.25.8" -> (4, 25, 8)
|
|
62
|
+
Ignores non-numeric parts and handles common version formats.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
version_string: Version string in the format "x.y.z" or "x.y.z<suffix>"
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Tuple of integers for the parsed version string.
|
|
69
|
+
"""
|
|
70
|
+
parts = []
|
|
71
|
+
for part in version_string.split("."):
|
|
72
|
+
try:
|
|
73
|
+
parts.append(int(part))
|
|
74
|
+
except ValueError:
|
|
75
|
+
# If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here.
|
|
76
|
+
# This is a simplification compared to 'packaging.parse_version', but sufficient
|
|
77
|
+
# for comparing strictly numeric semantic versions.
|
|
78
|
+
break
|
|
79
|
+
return tuple(parts)
|
|
80
|
+
|
|
81
|
+
|
|
51
82
|
def get_dependency_version(
|
|
52
83
|
dependency_name: str,
|
|
53
84
|
) -> DependencyVersion:
|
|
54
85
|
"""Get the parsed version of an installed package dependency.
|
|
55
86
|
|
|
56
87
|
This function checks for an installed package and returns its version
|
|
57
|
-
as a
|
|
88
|
+
as a comparable tuple of integers object for safe comparison. It handles
|
|
58
89
|
both modern (Python 3.8+) and legacy (Python 3.7) environments.
|
|
59
90
|
|
|
60
91
|
Args:
|
|
61
92
|
dependency_name: The distribution name of the package (e.g., 'requests').
|
|
62
93
|
|
|
63
94
|
Returns:
|
|
64
|
-
A DependencyVersion namedtuple with `version` and
|
|
95
|
+
A DependencyVersion namedtuple with `version` (a tuple of integers) and
|
|
65
96
|
`version_string` attributes, or `DependencyVersion(None,
|
|
66
97
|
UNKNOWN_VERSION_STRING)` if the package is not found or
|
|
67
98
|
another error occurs during version discovery.
|
|
68
99
|
|
|
69
100
|
"""
|
|
70
101
|
try:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
version_string = metadata.version(dependency_name)
|
|
75
|
-
return DependencyVersion(parse_version(version_string), version_string)
|
|
76
|
-
|
|
77
|
-
# TODO(https://github.com/googleapis/python-api-core/issues/835): Remove
|
|
78
|
-
# this code path once we drop support for Python 3.7
|
|
79
|
-
else: # pragma: NO COVER
|
|
80
|
-
# Use pkg_resources, which is part of setuptools.
|
|
81
|
-
import pkg_resources
|
|
82
|
-
|
|
83
|
-
version_string = pkg_resources.get_distribution(dependency_name).version
|
|
84
|
-
return DependencyVersion(parse_version(version_string), version_string)
|
|
85
|
-
|
|
102
|
+
version_string: str = metadata.version(dependency_name)
|
|
103
|
+
parsed_version = parse_version_to_tuple(version_string)
|
|
104
|
+
return DependencyVersion(parsed_version, version_string)
|
|
86
105
|
except Exception:
|
|
106
|
+
# Catch exceptions from metadata.version() (e.g., PackageNotFoundError)
|
|
107
|
+
# or errors during parse_version_to_tuple
|
|
87
108
|
return DependencyVersion(None, UNKNOWN_VERSION_STRING)
|
|
88
109
|
|
|
89
110
|
|
|
@@ -132,10 +153,14 @@ def warn_deprecation_for_versions_less_than(
|
|
|
132
153
|
or not minimum_fully_supported_version
|
|
133
154
|
): # pragma: NO COVER
|
|
134
155
|
return
|
|
156
|
+
|
|
135
157
|
dependency_version = get_dependency_version(dependency_import_package)
|
|
136
158
|
if not dependency_version.version:
|
|
137
159
|
return
|
|
138
|
-
|
|
160
|
+
|
|
161
|
+
if dependency_version.version < parse_version_to_tuple(
|
|
162
|
+
minimum_fully_supported_version
|
|
163
|
+
):
|
|
139
164
|
(
|
|
140
165
|
dependency_package,
|
|
141
166
|
dependency_distribution_package,
|
{google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/_python_version_support.py
RENAMED
|
@@ -16,12 +16,16 @@
|
|
|
16
16
|
|
|
17
17
|
import datetime
|
|
18
18
|
import enum
|
|
19
|
+
import logging
|
|
19
20
|
import warnings
|
|
20
21
|
import sys
|
|
21
22
|
import textwrap
|
|
22
23
|
from typing import Any, List, NamedTuple, Optional, Dict, Tuple
|
|
23
24
|
|
|
24
25
|
|
|
26
|
+
_LOGGER = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
25
29
|
class PythonVersionStatus(enum.Enum):
|
|
26
30
|
"""Support status of a Python version in this client library artifact release.
|
|
27
31
|
|
|
@@ -147,9 +151,11 @@ def _flatten_message(text: str) -> str:
|
|
|
147
151
|
return " ".join(textwrap.dedent(text).strip().split())
|
|
148
152
|
|
|
149
153
|
|
|
150
|
-
# TODO(https://github.com/googleapis/python-api-core/issues/835):
|
|
151
|
-
# no longer support Python 3.
|
|
152
|
-
|
|
154
|
+
# TODO(https://github.com/googleapis/python-api-core/issues/835):
|
|
155
|
+
# Remove once we no longer support Python 3.9.
|
|
156
|
+
# `importlib.metadata.packages_distributions()` is only supported in Python 3.10 and newer
|
|
157
|
+
# https://docs.python.org/3/library/importlib.metadata.html#importlib.metadata.packages_distributions
|
|
158
|
+
if sys.version_info < (3, 10):
|
|
153
159
|
|
|
154
160
|
def _get_pypi_package_name(module_name): # pragma: NO COVER
|
|
155
161
|
"""Determine the PyPI package name for a given module name."""
|
|
@@ -168,11 +174,14 @@ else:
|
|
|
168
174
|
if module_name in module_to_distributions: # pragma: NO COVER
|
|
169
175
|
# The value is a list of distribution names, take the first one
|
|
170
176
|
return module_to_distributions[module_name][0]
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
177
|
+
except Exception as e: # pragma: NO COVER
|
|
178
|
+
_LOGGER.info(
|
|
179
|
+
"An error occurred while determining PyPI package name for %s: %s",
|
|
180
|
+
module_name,
|
|
181
|
+
e,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
return None
|
|
176
185
|
|
|
177
186
|
|
|
178
187
|
def _get_distribution_and_import_packages(import_package: str) -> Tuple[str, Any]:
|
|
@@ -281,11 +281,11 @@ class BidiRpc(BidiRpcBase):
|
|
|
281
281
|
|
|
282
282
|
def close(self):
|
|
283
283
|
"""Closes the stream."""
|
|
284
|
-
if self.call is None:
|
|
285
|
-
|
|
284
|
+
if self.call is not None:
|
|
285
|
+
self.call.cancel()
|
|
286
286
|
|
|
287
|
+
# Put None in request queue to signal termination.
|
|
287
288
|
self._request_queue.put(None)
|
|
288
|
-
self.call.cancel()
|
|
289
289
|
self._request_generator = None
|
|
290
290
|
self._initial_request = None
|
|
291
291
|
self._callbacks = []
|
|
@@ -197,11 +197,11 @@ class AsyncBidiRpc(BidiRpcBase):
|
|
|
197
197
|
|
|
198
198
|
async def close(self) -> None:
|
|
199
199
|
"""Closes the stream."""
|
|
200
|
-
if self.call is None:
|
|
201
|
-
|
|
200
|
+
if self.call is not None:
|
|
201
|
+
self.call.cancel()
|
|
202
202
|
|
|
203
|
+
# Put None in request queue to signal termination.
|
|
203
204
|
await self._request_queue.put(None)
|
|
204
|
-
self.call.cancel()
|
|
205
205
|
self._request_generator = None
|
|
206
206
|
self._initial_request = None
|
|
207
207
|
self._callbacks = []
|
|
@@ -300,16 +300,22 @@ class AbstractOperationsBaseClient(metaclass=AbstractOperationsBaseClientMeta):
|
|
|
300
300
|
client_options = client_options_lib.ClientOptions()
|
|
301
301
|
|
|
302
302
|
# Create SSL credentials for mutual TLS if needed.
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
"
|
|
309
|
-
)
|
|
303
|
+
if hasattr(mtls, "should_use_client_cert"):
|
|
304
|
+
use_client_cert = mtls.should_use_client_cert()
|
|
305
|
+
else:
|
|
306
|
+
# if unsupported, fallback to reading from env var
|
|
307
|
+
use_client_cert_str = os.getenv(
|
|
308
|
+
"GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"
|
|
309
|
+
).lower()
|
|
310
|
+
if use_client_cert_str not in ("true", "false"):
|
|
311
|
+
raise ValueError(
|
|
312
|
+
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be"
|
|
313
|
+
" either `true` or `false`"
|
|
314
|
+
)
|
|
315
|
+
use_client_cert = use_client_cert_str == "true"
|
|
310
316
|
client_cert_source_func = None
|
|
311
317
|
is_mtls = False
|
|
312
|
-
if use_client_cert
|
|
318
|
+
if use_client_cert:
|
|
313
319
|
if client_options.client_cert_source:
|
|
314
320
|
is_mtls = True
|
|
315
321
|
client_cert_source_func = client_options.client_cert_source
|
|
@@ -48,7 +48,7 @@ class ListOperationsPager(ListOperationsPagerBase):
|
|
|
48
48
|
request: operations_pb2.ListOperationsRequest,
|
|
49
49
|
response: operations_pb2.ListOperationsResponse,
|
|
50
50
|
*,
|
|
51
|
-
metadata: Sequence[Tuple[str, str]] = ()
|
|
51
|
+
metadata: Sequence[Tuple[str, str]] = (),
|
|
52
52
|
):
|
|
53
53
|
super().__init__(
|
|
54
54
|
method=method, request=request, response=response, metadata=metadata
|
{google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/pagers_async.py
RENAMED
|
@@ -48,7 +48,7 @@ class ListOperationsAsyncPager(ListOperationsPagerBase):
|
|
|
48
48
|
request: operations_pb2.ListOperationsRequest,
|
|
49
49
|
response: operations_pb2.ListOperationsResponse,
|
|
50
50
|
*,
|
|
51
|
-
metadata: Sequence[Tuple[str, str]] = ()
|
|
51
|
+
metadata: Sequence[Tuple[str, str]] = (),
|
|
52
52
|
):
|
|
53
53
|
super().__init__(
|
|
54
54
|
method=method, request=request, response=response, metadata=metadata
|
{google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/pagers_base.py
RENAMED
|
@@ -47,7 +47,7 @@ class ListOperationsPagerBase:
|
|
|
47
47
|
request: operations_pb2.ListOperationsRequest,
|
|
48
48
|
response: operations_pb2.ListOperationsResponse,
|
|
49
49
|
*,
|
|
50
|
-
metadata: Sequence[Tuple[str, str]] = ()
|
|
50
|
+
metadata: Sequence[Tuple[str, str]] = (),
|
|
51
51
|
):
|
|
52
52
|
"""Instantiate the pager.
|
|
53
53
|
|
{google_api_core-2.28.0 → google_api_core-2.29.0}/google/api_core/operations_v1/transports/base.py
RENAMED
|
@@ -119,8 +119,6 @@ class OperationsTransport(abc.ABC):
|
|
|
119
119
|
host += ":443" # pragma: NO COVER
|
|
120
120
|
self._host = host
|
|
121
121
|
|
|
122
|
-
scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES}
|
|
123
|
-
|
|
124
122
|
# Save the scopes.
|
|
125
123
|
self._scopes = scopes
|
|
126
124
|
|
|
@@ -133,12 +131,17 @@ class OperationsTransport(abc.ABC):
|
|
|
133
131
|
|
|
134
132
|
if credentials_file is not None:
|
|
135
133
|
credentials, _ = google.auth.load_credentials_from_file(
|
|
136
|
-
credentials_file,
|
|
134
|
+
credentials_file,
|
|
135
|
+
scopes=scopes,
|
|
136
|
+
quota_project_id=quota_project_id,
|
|
137
|
+
default_scopes=self.AUTH_SCOPES,
|
|
137
138
|
)
|
|
138
139
|
|
|
139
140
|
elif credentials is None:
|
|
140
141
|
credentials, _ = google.auth.default(
|
|
141
|
-
|
|
142
|
+
scopes=scopes,
|
|
143
|
+
quota_project_id=quota_project_id,
|
|
144
|
+
default_scopes=self.AUTH_SCOPES,
|
|
142
145
|
)
|
|
143
146
|
|
|
144
147
|
# If the credentials are service account credentials, then always try to use self signed JWT.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-api-core
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.29.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
|
|
@@ -30,6 +30,7 @@ Requires-Dist: proto-plus<2.0.0,>=1.22.3
|
|
|
30
30
|
Requires-Dist: proto-plus<2.0.0,>=1.25.0; python_version >= "3.13"
|
|
31
31
|
Requires-Dist: google-auth<3.0.0,>=2.14.1
|
|
32
32
|
Requires-Dist: requests<3.0.0,>=2.18.0
|
|
33
|
+
Requires-Dist: importlib_metadata>=1.4; python_version < "3.8"
|
|
33
34
|
Provides-Extra: async-rest
|
|
34
35
|
Requires-Dist: google-auth[aiohttp]<3.0.0,>=2.35.0; extra == "async-rest"
|
|
35
36
|
Provides-Extra: grpc
|
|
@@ -51,6 +51,9 @@ dependencies = [
|
|
|
51
51
|
"proto-plus >= 1.25.0, < 2.0.0; python_version >= '3.13'",
|
|
52
52
|
"google-auth >= 2.14.1, < 3.0.0",
|
|
53
53
|
"requests >= 2.18.0, < 3.0.0",
|
|
54
|
+
# TODO(https://github.com/googleapis/python-api-core/issues/835): Remove
|
|
55
|
+
# `importlib_metadata` once we drop support for Python 3.7
|
|
56
|
+
"importlib_metadata>=1.4; python_version<'3.8'",
|
|
54
57
|
]
|
|
55
58
|
dynamic = ["version"]
|
|
56
59
|
|
|
@@ -80,7 +83,7 @@ version = { attr = "google.api_core.version.__version__" }
|
|
|
80
83
|
include = ["google*"]
|
|
81
84
|
|
|
82
85
|
[tool.mypy]
|
|
83
|
-
python_version = "3.
|
|
86
|
+
python_version = "3.14"
|
|
84
87
|
namespace_packages = true
|
|
85
88
|
ignore_missing_imports = true
|
|
86
89
|
|
|
@@ -88,6 +91,8 @@ ignore_missing_imports = true
|
|
|
88
91
|
filterwarnings = [
|
|
89
92
|
# treat all warnings as errors
|
|
90
93
|
"error",
|
|
94
|
+
# Prevent Python version warnings from interfering with tests
|
|
95
|
+
"ignore:.* Python version .*:FutureWarning",
|
|
91
96
|
# Remove once https://github.com/pytest-dev/pytest-cov/issues/621 is fixed
|
|
92
97
|
"ignore:.*The --rsyncdir command line argument and rsyncdirs config variable are deprecated:DeprecationWarning",
|
|
93
98
|
# Remove once https://github.com/protocolbuffers/protobuf/issues/12186 is fixed
|
|
@@ -260,7 +260,7 @@ async def test_wrap_method_with_overriding_timeout_as_a_number():
|
|
|
260
260
|
actual_timeout = method.call_args[1]["timeout"]
|
|
261
261
|
metadata = method.call_args[1]["metadata"]
|
|
262
262
|
assert metadata == mock.ANY
|
|
263
|
-
assert actual_timeout == pytest.approx(22, abs=0.
|
|
263
|
+
assert actual_timeout == pytest.approx(22, abs=0.05)
|
|
264
264
|
|
|
265
265
|
|
|
266
266
|
@pytest.mark.asyncio
|
|
@@ -255,6 +255,21 @@ class TestAsyncBidiRpc:
|
|
|
255
255
|
assert bidi_rpc._initial_request is None
|
|
256
256
|
assert not bidi_rpc._callbacks
|
|
257
257
|
|
|
258
|
+
@pytest.mark.asyncio
|
|
259
|
+
async def test_close_with_no_rpc(self):
|
|
260
|
+
bidi_rpc = bidi_async.AsyncBidiRpc(None)
|
|
261
|
+
|
|
262
|
+
await bidi_rpc.close()
|
|
263
|
+
|
|
264
|
+
assert bidi_rpc.call is None
|
|
265
|
+
assert bidi_rpc.is_active is False
|
|
266
|
+
# ensure the request queue was signaled to stop.
|
|
267
|
+
assert bidi_rpc.pending_requests == 1
|
|
268
|
+
assert await bidi_rpc._request_queue.get() is None
|
|
269
|
+
# ensure request and callbacks are cleaned up
|
|
270
|
+
assert bidi_rpc._initial_request is None
|
|
271
|
+
assert not bidi_rpc._callbacks
|
|
272
|
+
|
|
258
273
|
@pytest.mark.asyncio
|
|
259
274
|
async def test_close_no_rpc(self):
|
|
260
275
|
bidi_rpc = bidi_async.AsyncBidiRpc(None)
|
|
@@ -17,6 +17,7 @@ try:
|
|
|
17
17
|
from unittest.mock import AsyncMock # pragma: NO COVER # noqa: F401
|
|
18
18
|
except ImportError: # pragma: NO COVER
|
|
19
19
|
import mock # type: ignore
|
|
20
|
+
from ..helpers import warn_deprecated_credentials_file
|
|
20
21
|
import pytest # noqa: I202
|
|
21
22
|
|
|
22
23
|
try:
|
|
@@ -522,11 +523,12 @@ def test_create_channel_explicit_with_duplicate_credentials():
|
|
|
522
523
|
target = "example:443"
|
|
523
524
|
|
|
524
525
|
with pytest.raises(exceptions.DuplicateCredentialArgs) as excinfo:
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
526
|
+
with warn_deprecated_credentials_file():
|
|
527
|
+
grpc_helpers_async.create_channel(
|
|
528
|
+
target,
|
|
529
|
+
credentials_file="credentials.json",
|
|
530
|
+
credentials=mock.sentinel.credentials,
|
|
531
|
+
)
|
|
530
532
|
|
|
531
533
|
assert "mutually exclusive" in str(excinfo.value)
|
|
532
534
|
|
|
@@ -641,9 +643,10 @@ def test_create_channel_with_credentials_file(
|
|
|
641
643
|
credentials_file = "/path/to/credentials/file.json"
|
|
642
644
|
composite_creds = composite_creds_call.return_value
|
|
643
645
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
646
|
+
with warn_deprecated_credentials_file():
|
|
647
|
+
channel = grpc_helpers_async.create_channel(
|
|
648
|
+
target, credentials_file=credentials_file
|
|
649
|
+
)
|
|
647
650
|
|
|
648
651
|
google.auth.load_credentials_from_file.assert_called_once_with(
|
|
649
652
|
credentials_file, scopes=None, default_scopes=None
|
|
@@ -670,9 +673,10 @@ def test_create_channel_with_credentials_file_and_scopes(
|
|
|
670
673
|
credentials_file = "/path/to/credentials/file.json"
|
|
671
674
|
composite_creds = composite_creds_call.return_value
|
|
672
675
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
+
with warn_deprecated_credentials_file():
|
|
677
|
+
channel = grpc_helpers_async.create_channel(
|
|
678
|
+
target, credentials_file=credentials_file, scopes=scopes
|
|
679
|
+
)
|
|
676
680
|
|
|
677
681
|
google.auth.load_credentials_from_file.assert_called_once_with(
|
|
678
682
|
credentials_file, scopes=scopes, default_scopes=None
|
|
@@ -699,9 +703,10 @@ def test_create_channel_with_credentials_file_and_default_scopes(
|
|
|
699
703
|
credentials_file = "/path/to/credentials/file.json"
|
|
700
704
|
composite_creds = composite_creds_call.return_value
|
|
701
705
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
706
|
+
with warn_deprecated_credentials_file():
|
|
707
|
+
channel = grpc_helpers_async.create_channel(
|
|
708
|
+
target, credentials_file=credentials_file, default_scopes=default_scopes
|
|
709
|
+
)
|
|
705
710
|
|
|
706
711
|
google.auth.load_credentials_from_file.assert_called_once_with(
|
|
707
712
|
credentials_file, scopes=None, default_scopes=default_scopes
|
{google_api_core-2.28.0 → google_api_core-2.29.0}/tests/asyncio/test_rest_streaming_async.py
RENAMED
|
@@ -292,7 +292,6 @@ async def test_next_escaped_characters_in_string(
|
|
|
292
292
|
@pytest.mark.asyncio
|
|
293
293
|
@pytest.mark.parametrize("response_type", [EchoResponse, httpbody_pb2.HttpBody])
|
|
294
294
|
async def test_next_not_array(response_type):
|
|
295
|
-
|
|
296
295
|
data = '{"hello": 0}'
|
|
297
296
|
with mock.patch.object(
|
|
298
297
|
ResponseMock, "content", return_value=mock_async_gen(data)
|
|
@@ -352,7 +351,6 @@ async def test_check_buffer(response_type, return_value):
|
|
|
352
351
|
@pytest.mark.asyncio
|
|
353
352
|
@pytest.mark.parametrize("response_type", [EchoResponse, httpbody_pb2.HttpBody])
|
|
354
353
|
async def test_next_html(response_type):
|
|
355
|
-
|
|
356
354
|
data = "<!DOCTYPE html><html></html>"
|
|
357
355
|
with mock.patch.object(
|
|
358
356
|
ResponseMock, "content", return_value=mock_async_gen(data)
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
"""Helpers for tests"""
|
|
16
16
|
|
|
17
|
+
import functools
|
|
17
18
|
import logging
|
|
19
|
+
import pytest # noqa: I202
|
|
18
20
|
from typing import List
|
|
19
21
|
|
|
20
22
|
import proto
|
|
@@ -69,3 +71,12 @@ def parse_responses(response_message_cls, all_responses: List[proto.Message]) ->
|
|
|
69
71
|
logging.info(f"Sending JSON stream: {json_responses}")
|
|
70
72
|
ret_val = "[{}]".format(",".join(json_responses))
|
|
71
73
|
return bytes(ret_val, "utf-8")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
warn_deprecated_credentials_file = functools.partial(
|
|
77
|
+
# This is used to test that the auth credentials file deprecation
|
|
78
|
+
# warning is emitted as expected.
|
|
79
|
+
pytest.warns,
|
|
80
|
+
DeprecationWarning,
|
|
81
|
+
match="argument is deprecated because of a potential security risk",
|
|
82
|
+
)
|
|
@@ -192,6 +192,7 @@ def test_wrap_method_with_overriding_retry_timeout_compression(unused_sleep):
|
|
|
192
192
|
)
|
|
193
193
|
|
|
194
194
|
|
|
195
|
+
@pytest.mark.skip(reason="Known flaky due to floating point comparison. #866")
|
|
195
196
|
def test_wrap_method_with_overriding_timeout_as_a_number():
|
|
196
197
|
method = mock.Mock(spec=["__call__"], return_value=42)
|
|
197
198
|
default_retry = retry.Retry()
|
|
@@ -200,6 +201,8 @@ def test_wrap_method_with_overriding_timeout_as_a_number():
|
|
|
200
201
|
method, default_retry, default_timeout
|
|
201
202
|
)
|
|
202
203
|
|
|
204
|
+
# Using "result = wrapped_method(timeout=22)" fails since wrapped_method
|
|
205
|
+
# does floating point calculations that results in 21.987.. instead of 22
|
|
203
206
|
result = wrapped_method(timeout=22)
|
|
204
207
|
|
|
205
208
|
assert result == 42
|
|
@@ -210,6 +213,24 @@ def test_wrap_method_with_overriding_timeout_as_a_number():
|
|
|
210
213
|
assert actual_timeout == pytest.approx(22, abs=0.01)
|
|
211
214
|
|
|
212
215
|
|
|
216
|
+
def test_wrap_method_with_overriding_constant_timeout():
|
|
217
|
+
method = mock.Mock(spec=["__call__"], return_value=42)
|
|
218
|
+
default_retry = retry.Retry()
|
|
219
|
+
default_timeout = timeout.ConstantTimeout(60)
|
|
220
|
+
wrapped_method = google.api_core.gapic_v1.method.wrap_method(
|
|
221
|
+
method, default_retry, default_timeout
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
result = wrapped_method(timeout=timeout.ConstantTimeout(22))
|
|
225
|
+
|
|
226
|
+
assert result == 42
|
|
227
|
+
|
|
228
|
+
actual_timeout = method.call_args[1]["timeout"]
|
|
229
|
+
metadata = method.call_args[1]["metadata"]
|
|
230
|
+
assert metadata == mock.ANY
|
|
231
|
+
assert actual_timeout == 22
|
|
232
|
+
|
|
233
|
+
|
|
213
234
|
def test_wrap_method_with_call():
|
|
214
235
|
method = mock.Mock()
|
|
215
236
|
mock_call = mock.Mock()
|
|
@@ -90,8 +90,8 @@ def test__urlencode_param(key, value, expected):
|
|
|
90
90
|
def test__urlencode_param_caching_performance():
|
|
91
91
|
import time
|
|
92
92
|
|
|
93
|
-
key = "key" *
|
|
94
|
-
value = "value" *
|
|
93
|
+
key = "key" * 10000
|
|
94
|
+
value = "value" * 10000
|
|
95
95
|
# time with empty cache
|
|
96
96
|
start_time = time.perf_counter()
|
|
97
97
|
routing_header._urlencode_param(key, value)
|