Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-google-api-core for 
openSUSE:Factory checked in at 2026-01-19 18:38:49
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-google-api-core (Old)
 and      /work/SRC/openSUSE:Factory/.python-google-api-core.new.1928 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-google-api-core"

Mon Jan 19 18:38:49 2026 rev:45 rq:1328093 version:2.29.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-google-api-core/python-google-api-core.changes
    2025-10-29 21:07:01.843569265 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-google-api-core.new.1928/python-google-api-core.changes
  2026-01-19 18:42:45.941628758 +0100
@@ -1,0 +2,23 @@
+Mon Jan 19 13:44:31 UTC 2026 - Dirk Müller <[email protected]>
+
+- fix tests
+
+-------------------------------------------------------------------
+Mon Jan 12 10:41:08 UTC 2026 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to 2.29.0
+  * Auto enable mTLS when supported certificates are detected (#869)
+  * make parse_version_to_tuple public (#864)
+  * flaky tests due to imprecision in floating point calculation and
+    performance test setup (#865)
+  * remove call to importlib.metadata.packages_distributions() for py38/py39 
(#859)
+  * Log version check errors (#858)
+  * closes tailing streams in bidi classes. (#851)
+
+-------------------------------------------------------------------
+Mon Nov  3 11:17:52 UTC 2025 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to 2.28.1
+  * Remove dependency on packaging and pkg_resources (#852)
+
+-------------------------------------------------------------------

Old:
----
  google_api_core-2.28.0.tar.gz

New:
----
  google_api_core-2.29.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-google-api-core.spec ++++++
--- /var/tmp/diff_new_pack.AGKHyL/_old  2026-01-19 18:42:46.505652095 +0100
+++ /var/tmp/diff_new_pack.AGKHyL/_new  2026-01-19 18:42:46.509652261 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-google-api-core
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -26,7 +26,7 @@
 %endif
 %{?sle15_python_module_pythons}
 Name:           python-google-api-core
-Version:        2.28.0
+Version:        2.29.0
 Release:        0
 Summary:        Google API client core library
 License:        Apache-2.0
@@ -76,7 +76,8 @@
 
 %check
 %if %{with test}
-%pytest
+# test_get_dependency_version: requires mocker which is unpackaged
+%pytest -k "not test_get_dependency_version"
 %endif
 
 %if !%{with test}

++++++ google_api_core-2.28.0.tar.gz -> google_api_core-2.29.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google_api_core-2.28.0/PKG-INFO 
new/google_api_core-2.29.0/PKG-INFO
--- old/google_api_core-2.28.0/PKG-INFO 2025-10-27 23:38:26.463393000 +0100
+++ new/google_api_core-2.29.0/PKG-INFO 2026-01-08 23:09:05.462095700 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: google-api-core
-Version: 2.28.0
+Version: 2.29.0
 Summary: Google API client core library
 Author-email: Google LLC <[email protected]>
 License: Apache 2.0
@@ -30,6 +30,7 @@
 Requires-Dist: proto-plus<2.0.0,>=1.25.0; python_version >= "3.13"
 Requires-Dist: google-auth<3.0.0,>=2.14.1
 Requires-Dist: requests<3.0.0,>=2.18.0
+Requires-Dist: importlib_metadata>=1.4; python_version < "3.8"
 Provides-Extra: async-rest
 Requires-Dist: google-auth[aiohttp]<3.0.0,>=2.35.0; extra == "async-rest"
 Provides-Extra: grpc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google_api_core-2.28.0/google/api_core/__init__.py 
new/google_api_core-2.29.0/google/api_core/__init__.py
--- old/google_api_core-2.28.0/google/api_core/__init__.py      2025-10-27 
23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/__init__.py      2026-01-08 
23:08:42.000000000 +0100
@@ -30,6 +30,7 @@
 # expose dependency checks for external callers
 check_python_version = _python_version_support.check_python_version
 check_dependency_versions = _python_package_support.check_dependency_versions
+parse_version_to_tuple = _python_package_support.parse_version_to_tuple
 warn_deprecation_for_versions_less_than = (
     _python_package_support.warn_deprecation_for_versions_less_than
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/google/api_core/_python_package_support.py 
new/google_api_core-2.29.0/google/api_core/_python_package_support.py
--- old/google_api_core-2.28.0/google/api_core/_python_package_support.py       
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/_python_package_support.py       
2026-01-08 23:08:42.000000000 +0100
@@ -16,7 +16,7 @@
 
 import warnings
 import sys
-from typing import Optional
+from typing import Optional, Tuple
 
 from collections import namedtuple
 
@@ -25,7 +25,14 @@
     _get_distribution_and_import_packages,
 )
 
-from packaging.version import parse as parse_version
+if sys.version_info >= (3, 8):
+    from importlib import metadata
+else:
+    # TODO(https://github.com/googleapis/python-api-core/issues/835): Remove
+    # this code path once we drop support for Python 3.7
+    import importlib_metadata as metadata
+
+ParsedVersion = Tuple[int, ...]
 
 # Here we list all the packages for which we want to issue warnings
 # about deprecated and unsupported versions.
@@ -48,42 +55,56 @@
 UNKNOWN_VERSION_STRING = "--"
 
 
+def parse_version_to_tuple(version_string: str) -> ParsedVersion:
+    """Safely converts a semantic version string to a comparable tuple of 
integers.
+
+    Example: "4.25.8" -> (4, 25, 8)
+    Ignores non-numeric parts and handles common version formats.
+
+    Args:
+        version_string: Version string in the format "x.y.z" or "x.y.z<suffix>"
+
+    Returns:
+        Tuple of integers for the parsed version string.
+    """
+    parts = []
+    for part in version_string.split("."):
+        try:
+            parts.append(int(part))
+        except ValueError:
+            # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here.
+            # This is a simplification compared to 'packaging.parse_version', 
but sufficient
+            # for comparing strictly numeric semantic versions.
+            break
+    return tuple(parts)
+
+
 def get_dependency_version(
     dependency_name: str,
 ) -> DependencyVersion:
     """Get the parsed version of an installed package dependency.
 
     This function checks for an installed package and returns its version
-    as a `packaging.version.Version` object for safe comparison. It handles
+    as a comparable tuple of integers object for safe comparison. It handles
     both modern (Python 3.8+) and legacy (Python 3.7) environments.
 
     Args:
         dependency_name: The distribution name of the package (e.g., 
'requests').
 
     Returns:
-        A DependencyVersion namedtuple with `version` and
+        A DependencyVersion namedtuple with `version`  (a tuple of integers) 
and
         `version_string` attributes, or `DependencyVersion(None,
         UNKNOWN_VERSION_STRING)` if the package is not found or
         another error occurs during version discovery.
 
     """
     try:
-        if sys.version_info >= (3, 8):
-            from importlib import metadata
-
-            version_string = metadata.version(dependency_name)
-            return DependencyVersion(parse_version(version_string), 
version_string)
-
-        # TODO(https://github.com/googleapis/python-api-core/issues/835): 
Remove
-        # this code path once we drop support for Python 3.7
-        else:  # pragma: NO COVER
-            # Use pkg_resources, which is part of setuptools.
-            import pkg_resources
-
-            version_string = 
pkg_resources.get_distribution(dependency_name).version
-            return DependencyVersion(parse_version(version_string), 
version_string)
-
+        version_string: str = metadata.version(dependency_name)
+        parsed_version = parse_version_to_tuple(version_string)
+        return DependencyVersion(parsed_version, version_string)
     except Exception:
+        # Catch exceptions from metadata.version() (e.g., PackageNotFoundError)
+        # or errors during parse_version_to_tuple
         return DependencyVersion(None, UNKNOWN_VERSION_STRING)
 
 
@@ -132,10 +153,14 @@
         or not minimum_fully_supported_version
     ):  # pragma: NO COVER
         return
+
     dependency_version = get_dependency_version(dependency_import_package)
     if not dependency_version.version:
         return
-    if dependency_version.version < 
parse_version(minimum_fully_supported_version):
+
+    if dependency_version.version < parse_version_to_tuple(
+        minimum_fully_supported_version
+    ):
         (
             dependency_package,
             dependency_distribution_package,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/google/api_core/_python_version_support.py 
new/google_api_core-2.29.0/google/api_core/_python_version_support.py
--- old/google_api_core-2.28.0/google/api_core/_python_version_support.py       
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/_python_version_support.py       
2026-01-08 23:08:42.000000000 +0100
@@ -16,12 +16,16 @@
 
 import datetime
 import enum
+import logging
 import warnings
 import sys
 import textwrap
 from typing import Any, List, NamedTuple, Optional, Dict, Tuple
 
 
+_LOGGER = logging.getLogger(__name__)
+
+
 class PythonVersionStatus(enum.Enum):
     """Support status of a Python version in this client library artifact 
release.
 
@@ -147,9 +151,11 @@
     return " ".join(textwrap.dedent(text).strip().split())
 
 
-# TODO(https://github.com/googleapis/python-api-core/issues/835): Remove once 
we
-# no longer support Python 3.7
-if sys.version_info < (3, 8):
+# TODO(https://github.com/googleapis/python-api-core/issues/835):
+# Remove once we no longer support Python 3.9.
+# `importlib.metadata.packages_distributions()` is only supported in Python 
3.10 and newer
+# 
https://docs.python.org/3/library/importlib.metadata.html#importlib.metadata.packages_distributions
+if sys.version_info < (3, 10):
 
     def _get_pypi_package_name(module_name):  # pragma: NO COVER
         """Determine the PyPI package name for a given module name."""
@@ -168,11 +174,14 @@
             if module_name in module_to_distributions:  # pragma: NO COVER
                 # The value is a list of distribution names, take the first one
                 return module_to_distributions[module_name][0]
-            else:
-                return None  # Module not found in the mapping
-        except Exception as e:
-            print(f"An error occurred: {e}")
-            return None
+        except Exception as e:  # pragma: NO COVER
+            _LOGGER.info(
+                "An error occurred while determining PyPI package name for %s: 
%s",
+                module_name,
+                e,
+            )
+
+        return None
 
 
 def _get_distribution_and_import_packages(import_package: str) -> Tuple[str, 
Any]:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google_api_core-2.28.0/google/api_core/bidi.py 
new/google_api_core-2.29.0/google/api_core/bidi.py
--- old/google_api_core-2.28.0/google/api_core/bidi.py  2025-10-27 
23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/bidi.py  2026-01-08 
23:08:42.000000000 +0100
@@ -281,11 +281,11 @@
 
     def close(self):
         """Closes the stream."""
-        if self.call is None:
-            return
+        if self.call is not None:
+            self.call.cancel()
 
+        # Put None in request queue to signal termination.
         self._request_queue.put(None)
-        self.call.cancel()
         self._request_generator = None
         self._initial_request = None
         self._callbacks = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google_api_core-2.28.0/google/api_core/bidi_async.py 
new/google_api_core-2.29.0/google/api_core/bidi_async.py
--- old/google_api_core-2.28.0/google/api_core/bidi_async.py    2025-10-27 
23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/bidi_async.py    2026-01-08 
23:08:42.000000000 +0100
@@ -197,11 +197,11 @@
 
     async def close(self) -> None:
         """Closes the stream."""
-        if self.call is None:
-            return
+        if self.call is not None:
+            self.call.cancel()
 
+        # Put None in request queue to signal termination.
         await self._request_queue.put(None)
-        self.call.cancel()
         self._request_generator = None
         self._initial_request = None
         self._callbacks = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/google/api_core/grpc_helpers_async.py 
new/google_api_core-2.29.0/google/api_core/grpc_helpers_async.py
--- old/google_api_core-2.28.0/google/api_core/grpc_helpers_async.py    
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/grpc_helpers_async.py    
2026-01-08 23:08:42.000000000 +0100
@@ -220,7 +220,7 @@
     default_host=None,
     compression=None,
     attempt_direct_path: Optional[bool] = False,
-    **kwargs
+    **kwargs,
 ):
     """Create an AsyncIO secure channel with credentials.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google_api_core-2.28.0/google/api_core/operation.py 
new/google_api_core-2.29.0/google/api_core/operation.py
--- old/google_api_core-2.28.0/google/api_core/operation.py     2025-10-27 
23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/operation.py     2026-01-08 
23:08:42.000000000 +0100
@@ -78,7 +78,7 @@
         result_type,
         metadata_type=None,
         polling=polling.DEFAULT_POLLING,
-        **kwargs
+        **kwargs,
     ):
         super(Operation, self).__init__(polling=polling, **kwargs)
         self._operation = operation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/google/api_core/operations_v1/abstract_operations_base_client.py
 
new/google_api_core-2.29.0/google/api_core/operations_v1/abstract_operations_base_client.py
--- 
old/google_api_core-2.28.0/google/api_core/operations_v1/abstract_operations_base_client.py
 2025-10-27 23:37:20.000000000 +0100
+++ 
new/google_api_core-2.29.0/google/api_core/operations_v1/abstract_operations_base_client.py
 2026-01-08 23:08:42.000000000 +0100
@@ -300,16 +300,22 @@
             client_options = client_options_lib.ClientOptions()
 
         # Create SSL credentials for mutual TLS if needed.
-        use_client_cert = os.getenv(
-            "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"
-        ).lower()
-        if use_client_cert not in ("true", "false"):
-            raise ValueError(
-                "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must 
be either `true` or `false`"
-            )
+        if hasattr(mtls, "should_use_client_cert"):
+            use_client_cert = mtls.should_use_client_cert()
+        else:
+            # 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`"
+                )
+            use_client_cert = use_client_cert_str == "true"
         client_cert_source_func = None
         is_mtls = False
-        if use_client_cert == "true":
+        if use_client_cert:
             if client_options.client_cert_source:
                 is_mtls = True
                 client_cert_source_func = client_options.client_cert_source
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/google/api_core/operations_v1/pagers.py 
new/google_api_core-2.29.0/google/api_core/operations_v1/pagers.py
--- old/google_api_core-2.28.0/google/api_core/operations_v1/pagers.py  
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/operations_v1/pagers.py  
2026-01-08 23:08:42.000000000 +0100
@@ -48,7 +48,7 @@
         request: operations_pb2.ListOperationsRequest,
         response: operations_pb2.ListOperationsResponse,
         *,
-        metadata: Sequence[Tuple[str, str]] = ()
+        metadata: Sequence[Tuple[str, str]] = (),
     ):
         super().__init__(
             method=method, request=request, response=response, 
metadata=metadata
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/google/api_core/operations_v1/pagers_async.py 
new/google_api_core-2.29.0/google/api_core/operations_v1/pagers_async.py
--- old/google_api_core-2.28.0/google/api_core/operations_v1/pagers_async.py    
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/operations_v1/pagers_async.py    
2026-01-08 23:08:42.000000000 +0100
@@ -48,7 +48,7 @@
         request: operations_pb2.ListOperationsRequest,
         response: operations_pb2.ListOperationsResponse,
         *,
-        metadata: Sequence[Tuple[str, str]] = ()
+        metadata: Sequence[Tuple[str, str]] = (),
     ):
         super().__init__(
             method=method, request=request, response=response, 
metadata=metadata
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/google/api_core/operations_v1/pagers_base.py 
new/google_api_core-2.29.0/google/api_core/operations_v1/pagers_base.py
--- old/google_api_core-2.28.0/google/api_core/operations_v1/pagers_base.py     
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/operations_v1/pagers_base.py     
2026-01-08 23:08:42.000000000 +0100
@@ -47,7 +47,7 @@
         request: operations_pb2.ListOperationsRequest,
         response: operations_pb2.ListOperationsResponse,
         *,
-        metadata: Sequence[Tuple[str, str]] = ()
+        metadata: Sequence[Tuple[str, str]] = (),
     ):
         """Instantiate the pager.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/google/api_core/operations_v1/transports/base.py 
new/google_api_core-2.29.0/google/api_core/operations_v1/transports/base.py
--- old/google_api_core-2.28.0/google/api_core/operations_v1/transports/base.py 
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/operations_v1/transports/base.py 
2026-01-08 23:08:42.000000000 +0100
@@ -119,8 +119,6 @@
             host += ":443"  # pragma: NO COVER
         self._host = host
 
-        scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES}
-
         # Save the scopes.
         self._scopes = scopes
 
@@ -133,12 +131,17 @@
 
         if credentials_file is not None:
             credentials, _ = google.auth.load_credentials_from_file(
-                credentials_file, **scopes_kwargs, 
quota_project_id=quota_project_id
+                credentials_file,
+                scopes=scopes,
+                quota_project_id=quota_project_id,
+                default_scopes=self.AUTH_SCOPES,
             )
 
         elif credentials is None:
             credentials, _ = google.auth.default(
-                **scopes_kwargs, quota_project_id=quota_project_id
+                scopes=scopes,
+                quota_project_id=quota_project_id,
+                default_scopes=self.AUTH_SCOPES,
             )
 
         # If the credentials are service account credentials, then always try 
to use self signed JWT.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google_api_core-2.28.0/google/api_core/version.py 
new/google_api_core-2.29.0/google/api_core/version.py
--- old/google_api_core-2.28.0/google/api_core/version.py       2025-10-27 
23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/google/api_core/version.py       2026-01-08 
23:08:42.000000000 +0100
@@ -12,4 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-__version__ = "2.28.0"
+__version__ = "2.29.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/google_api_core.egg-info/PKG-INFO 
new/google_api_core-2.29.0/google_api_core.egg-info/PKG-INFO
--- old/google_api_core-2.28.0/google_api_core.egg-info/PKG-INFO        
2025-10-27 23:38:26.000000000 +0100
+++ new/google_api_core-2.29.0/google_api_core.egg-info/PKG-INFO        
2026-01-08 23:09:05.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: google-api-core
-Version: 2.28.0
+Version: 2.29.0
 Summary: Google API client core library
 Author-email: Google LLC <[email protected]>
 License: Apache 2.0
@@ -30,6 +30,7 @@
 Requires-Dist: proto-plus<2.0.0,>=1.25.0; python_version >= "3.13"
 Requires-Dist: google-auth<3.0.0,>=2.14.1
 Requires-Dist: requests<3.0.0,>=2.18.0
+Requires-Dist: importlib_metadata>=1.4; python_version < "3.8"
 Provides-Extra: async-rest
 Requires-Dist: google-auth[aiohttp]<3.0.0,>=2.35.0; extra == "async-rest"
 Provides-Extra: grpc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/google_api_core.egg-info/requires.txt 
new/google_api_core-2.29.0/google_api_core.egg-info/requires.txt
--- old/google_api_core-2.28.0/google_api_core.egg-info/requires.txt    
2025-10-27 23:38:26.000000000 +0100
+++ new/google_api_core-2.29.0/google_api_core.egg-info/requires.txt    
2026-01-08 23:09:05.000000000 +0100
@@ -4,6 +4,9 @@
 google-auth<3.0.0,>=2.14.1
 requests<3.0.0,>=2.18.0
 
+[:python_version < "3.8"]
+importlib_metadata>=1.4
+
 [:python_version >= "3.13"]
 proto-plus<2.0.0,>=1.25.0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google_api_core-2.28.0/pyproject.toml 
new/google_api_core-2.29.0/pyproject.toml
--- old/google_api_core-2.28.0/pyproject.toml   2025-10-27 23:37:20.000000000 
+0100
+++ new/google_api_core-2.29.0/pyproject.toml   2026-01-08 23:08:42.000000000 
+0100
@@ -51,6 +51,9 @@
   "proto-plus >= 1.25.0, < 2.0.0; python_version >= '3.13'",
   "google-auth >= 2.14.1, < 3.0.0",
   "requests >= 2.18.0, < 3.0.0",
+  # TODO(https://github.com/googleapis/python-api-core/issues/835): Remove
+  # `importlib_metadata` once we drop support for Python 3.7
+  "importlib_metadata>=1.4; python_version<'3.8'",
 ]
 dynamic = ["version"]
 
@@ -80,7 +83,7 @@
 include = ["google*"]
 
 [tool.mypy]
-python_version = "3.7"
+python_version = "3.14"
 namespace_packages = true
 ignore_missing_imports = true
 
@@ -88,6 +91,8 @@
 filterwarnings = [
   # treat all warnings as errors
   "error",
+  # Prevent Python version warnings from interfering with tests
+  "ignore:.* Python version .*:FutureWarning",
   # Remove once https://github.com/pytest-dev/pytest-cov/issues/621 is fixed
   "ignore:.*The --rsyncdir command line argument and rsyncdirs config variable 
are deprecated:DeprecationWarning",
   # Remove once https://github.com/protocolbuffers/protobuf/issues/12186 is 
fixed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google_api_core-2.28.0/setup.cfg 
new/google_api_core-2.29.0/setup.cfg
--- old/google_api_core-2.28.0/setup.cfg        2025-10-27 23:38:26.463393000 
+0100
+++ new/google_api_core-2.29.0/setup.cfg        2026-01-08 23:09:05.463430000 
+0100
@@ -1,12 +1,3 @@
-[pytype]
-python_version = 3.7
-inputs = 
-       google/
-exclude = 
-       tests/
-output = .pytype/
-disable = pyi-error
-
 [egg_info]
 tag_build = 
 tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/asyncio/gapic/test_method_async.py 
new/google_api_core-2.29.0/tests/asyncio/gapic/test_method_async.py
--- old/google_api_core-2.28.0/tests/asyncio/gapic/test_method_async.py 
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/asyncio/gapic/test_method_async.py 
2026-01-08 23:08:42.000000000 +0100
@@ -260,7 +260,7 @@
     actual_timeout = method.call_args[1]["timeout"]
     metadata = method.call_args[1]["metadata"]
     assert metadata == mock.ANY
-    assert actual_timeout == pytest.approx(22, abs=0.01)
+    assert actual_timeout == pytest.approx(22, abs=0.05)
 
 
 @pytest.mark.asyncio
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/asyncio/test_bidi_async.py 
new/google_api_core-2.29.0/tests/asyncio/test_bidi_async.py
--- old/google_api_core-2.28.0/tests/asyncio/test_bidi_async.py 2025-10-27 
23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/asyncio/test_bidi_async.py 2026-01-08 
23:08:42.000000000 +0100
@@ -256,6 +256,21 @@
         assert not bidi_rpc._callbacks
 
     @pytest.mark.asyncio
+    async def test_close_with_no_rpc(self):
+        bidi_rpc = bidi_async.AsyncBidiRpc(None)
+
+        await bidi_rpc.close()
+
+        assert bidi_rpc.call is None
+        assert bidi_rpc.is_active is False
+        # ensure the request queue was signaled to stop.
+        assert bidi_rpc.pending_requests == 1
+        assert await bidi_rpc._request_queue.get() is None
+        # ensure request and callbacks are cleaned up
+        assert bidi_rpc._initial_request is None
+        assert not bidi_rpc._callbacks
+
+    @pytest.mark.asyncio
     async def test_close_no_rpc(self):
         bidi_rpc = bidi_async.AsyncBidiRpc(None)
         await bidi_rpc.close()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/asyncio/test_grpc_helpers_async.py 
new/google_api_core-2.29.0/tests/asyncio/test_grpc_helpers_async.py
--- old/google_api_core-2.28.0/tests/asyncio/test_grpc_helpers_async.py 
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/asyncio/test_grpc_helpers_async.py 
2026-01-08 23:08:42.000000000 +0100
@@ -17,6 +17,7 @@
     from unittest.mock import AsyncMock  # pragma: NO COVER  # noqa: F401
 except ImportError:  # pragma: NO COVER
     import mock  # type: ignore
+from ..helpers import warn_deprecated_credentials_file
 import pytest  # noqa: I202
 
 try:
@@ -522,11 +523,12 @@
     target = "example:443"
 
     with pytest.raises(exceptions.DuplicateCredentialArgs) as excinfo:
-        grpc_helpers_async.create_channel(
-            target,
-            credentials_file="credentials.json",
-            credentials=mock.sentinel.credentials,
-        )
+        with warn_deprecated_credentials_file():
+            grpc_helpers_async.create_channel(
+                target,
+                credentials_file="credentials.json",
+                credentials=mock.sentinel.credentials,
+            )
 
     assert "mutually exclusive" in str(excinfo.value)
 
@@ -641,9 +643,10 @@
     credentials_file = "/path/to/credentials/file.json"
     composite_creds = composite_creds_call.return_value
 
-    channel = grpc_helpers_async.create_channel(
-        target, credentials_file=credentials_file
-    )
+    with warn_deprecated_credentials_file():
+        channel = grpc_helpers_async.create_channel(
+            target, credentials_file=credentials_file
+        )
 
     google.auth.load_credentials_from_file.assert_called_once_with(
         credentials_file, scopes=None, default_scopes=None
@@ -670,9 +673,10 @@
     credentials_file = "/path/to/credentials/file.json"
     composite_creds = composite_creds_call.return_value
 
-    channel = grpc_helpers_async.create_channel(
-        target, credentials_file=credentials_file, scopes=scopes
-    )
+    with warn_deprecated_credentials_file():
+        channel = grpc_helpers_async.create_channel(
+            target, credentials_file=credentials_file, scopes=scopes
+        )
 
     google.auth.load_credentials_from_file.assert_called_once_with(
         credentials_file, scopes=scopes, default_scopes=None
@@ -699,9 +703,10 @@
     credentials_file = "/path/to/credentials/file.json"
     composite_creds = composite_creds_call.return_value
 
-    channel = grpc_helpers_async.create_channel(
-        target, credentials_file=credentials_file, 
default_scopes=default_scopes
-    )
+    with warn_deprecated_credentials_file():
+        channel = grpc_helpers_async.create_channel(
+            target, credentials_file=credentials_file, 
default_scopes=default_scopes
+        )
 
     google.auth.load_credentials_from_file.assert_called_once_with(
         credentials_file, scopes=None, default_scopes=default_scopes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/asyncio/test_rest_streaming_async.py 
new/google_api_core-2.29.0/tests/asyncio/test_rest_streaming_async.py
--- old/google_api_core-2.28.0/tests/asyncio/test_rest_streaming_async.py       
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/asyncio/test_rest_streaming_async.py       
2026-01-08 23:08:42.000000000 +0100
@@ -292,7 +292,6 @@
 @pytest.mark.asyncio
 @pytest.mark.parametrize("response_type", [EchoResponse, 
httpbody_pb2.HttpBody])
 async def test_next_not_array(response_type):
-
     data = '{"hello": 0}'
     with mock.patch.object(
         ResponseMock, "content", return_value=mock_async_gen(data)
@@ -352,7 +351,6 @@
 @pytest.mark.asyncio
 @pytest.mark.parametrize("response_type", [EchoResponse, 
httpbody_pb2.HttpBody])
 async def test_next_html(response_type):
-
     data = "<!DOCTYPE html><html></html>"
     with mock.patch.object(
         ResponseMock, "content", return_value=mock_async_gen(data)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google_api_core-2.28.0/tests/helpers.py 
new/google_api_core-2.29.0/tests/helpers.py
--- old/google_api_core-2.28.0/tests/helpers.py 2025-10-27 23:37:20.000000000 
+0100
+++ new/google_api_core-2.29.0/tests/helpers.py 2026-01-08 23:08:42.000000000 
+0100
@@ -14,7 +14,9 @@
 
 """Helpers for tests"""
 
+import functools
 import logging
+import pytest  # noqa: I202
 from typing import List
 
 import proto
@@ -69,3 +71,12 @@
     logging.info(f"Sending JSON stream: {json_responses}")
     ret_val = "[{}]".format(",".join(json_responses))
     return bytes(ret_val, "utf-8")
+
+
+warn_deprecated_credentials_file = functools.partial(
+    # This is used to test that the auth credentials file deprecation
+    # warning is emitted as expected.
+    pytest.warns,
+    DeprecationWarning,
+    match="argument is deprecated because of a potential security risk",
+)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/unit/gapic/test_method.py 
new/google_api_core-2.29.0/tests/unit/gapic/test_method.py
--- old/google_api_core-2.28.0/tests/unit/gapic/test_method.py  2025-10-27 
23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/unit/gapic/test_method.py  2026-01-08 
23:08:42.000000000 +0100
@@ -192,6 +192,7 @@
     )
 
 
[email protected](reason="Known flaky due to floating point comparison. #866")
 def test_wrap_method_with_overriding_timeout_as_a_number():
     method = mock.Mock(spec=["__call__"], return_value=42)
     default_retry = retry.Retry()
@@ -200,6 +201,8 @@
         method, default_retry, default_timeout
     )
 
+    # Using "result = wrapped_method(timeout=22)" fails since wrapped_method
+    # does floating point calculations that results in 21.987.. instead of 22
     result = wrapped_method(timeout=22)
 
     assert result == 42
@@ -210,6 +213,24 @@
     assert actual_timeout == pytest.approx(22, abs=0.01)
 
 
+def test_wrap_method_with_overriding_constant_timeout():
+    method = mock.Mock(spec=["__call__"], return_value=42)
+    default_retry = retry.Retry()
+    default_timeout = timeout.ConstantTimeout(60)
+    wrapped_method = google.api_core.gapic_v1.method.wrap_method(
+        method, default_retry, default_timeout
+    )
+
+    result = wrapped_method(timeout=timeout.ConstantTimeout(22))
+
+    assert result == 42
+
+    actual_timeout = method.call_args[1]["timeout"]
+    metadata = method.call_args[1]["metadata"]
+    assert metadata == mock.ANY
+    assert actual_timeout == 22
+
+
 def test_wrap_method_with_call():
     method = mock.Mock()
     mock_call = mock.Mock()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/unit/gapic/test_routing_header.py 
new/google_api_core-2.29.0/tests/unit/gapic/test_routing_header.py
--- old/google_api_core-2.28.0/tests/unit/gapic/test_routing_header.py  
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/unit/gapic/test_routing_header.py  
2026-01-08 23:08:42.000000000 +0100
@@ -90,8 +90,8 @@
 def test__urlencode_param_caching_performance():
     import time
 
-    key = "key" * 100
-    value = "value" * 100
+    key = "key" * 10000
+    value = "value" * 10000
     # time with empty cache
     start_time = time.perf_counter()
     routing_header._urlencode_param(key, value)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/unit/operations_v1/test_operations_rest_client.py
 
new/google_api_core-2.29.0/tests/unit/operations_v1/test_operations_rest_client.py
--- 
old/google_api_core-2.28.0/tests/unit/operations_v1/test_operations_rest_client.py
  2025-10-27 23:37:20.000000000 +0100
+++ 
new/google_api_core-2.29.0/tests/unit/operations_v1/test_operations_rest_client.py
  2026-01-08 23:08:42.000000000 +0100
@@ -23,6 +23,7 @@
 
 import pytest
 from typing import Any, List
+from ...helpers import warn_deprecated_credentials_file
 
 try:
     import grpc  # noqa: F401
@@ -34,6 +35,7 @@
 from google.api_core import client_options
 from google.api_core import exceptions as core_exceptions
 from google.api_core import gapic_v1
+from google.api_core import parse_version_to_tuple
 from google.api_core.operations_v1 import AbstractOperationsClient
 
 import google.auth
@@ -41,6 +43,7 @@
 from google.api_core.operations_v1 import pagers_async
 from google.api_core.operations_v1 import transports
 from google.auth import credentials as ga_credentials
+from google.auth import __version__ as auth_version
 from google.auth.exceptions import MutualTLSChannelError
 from google.longrunning import operations_pb2
 from google.oauth2 import service_account
@@ -225,7 +228,6 @@
     PYPARAM_CLIENT,
 )
 def test_operations_client_from_service_account_file(client_class):
-
     if "async" in str(client_class):
         # TODO(): Add support for service account creds to async REST 
transport.
         with pytest.raises(NotImplementedError):
@@ -345,12 +347,30 @@
         with pytest.raises(MutualTLSChannelError):
             client = client_class()
 
-    # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value.
+    # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value
     with mock.patch.dict(
         os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}
     ):
-        with pytest.raises(ValueError):
-            client = client_class()
+        # Test behavior for google.auth versions < 2.43.0.
+        # These versions do not have the updated mtls.should_use_client_cert 
logic.
+        # Verify that a ValueError is raised when 
GOOGLE_API_USE_CLIENT_CERTIFICATE
+        # is set to an unsupported value, as expected in these older versions.
+        if parse_version_to_tuple(auth_version) < (2, 43, 0):
+            with pytest.raises(ValueError):
+                client = client_class()
+        # Test behavior for google.auth versions >= 2.43.0.
+        # In these versions, if GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an
+        # unsupported value (e.g., not 'true' or 'false'), the expected 
behavior
+        # of the internal google.auth.mtls.should_use_client_cert() function
+        # is to return False. Expect should_use_client_cert to return False, so
+        # client creation should proceed without requiring a client 
certificate.
+        else:
+            with mock.patch.object(transport_class, "__init__") as patched:
+                patched.return_value = None
+                client = client_class(
+                    credentials=ga_credentials.AnonymousCredentials(),
+                    transport=transport_name,
+                )
 
     # Check the case quota_project_id is provided
     options = client_options.ClientOptions(quota_project_id="octopus")
@@ -369,7 +389,8 @@
         )
 
     # Check the case credentials_file is provided
-    options = client_options.ClientOptions(credentials_file="credentials.json")
+    with warn_deprecated_credentials_file():
+        options = 
client_options.ClientOptions(credentials_file="credentials.json")
     with mock.patch.object(transport_class, "__init__") as patched:
         patched.return_value = None
         client = client_class(client_options=options, transport=transport_name)
@@ -539,11 +560,13 @@
     client_class, transport_class, transport_name
 ):
     # Check the case credentials file is provided.
-    options = client_options.ClientOptions(credentials_file="credentials.json")
+    with warn_deprecated_credentials_file():
+        options = 
client_options.ClientOptions(credentials_file="credentials.json")
     if "async" in str(client_class):
         # TODO(): Add support for credentials file to async REST transport.
         with pytest.raises(core_exceptions.AsyncRestUnsupportedParameterError):
-            client_class(client_options=options, transport=transport_name)
+            with warn_deprecated_credentials_file():
+                client_class(client_options=options, transport=transport_name)
     else:
         with mock.patch.object(transport_class, "__init__") as patched:
             patched.return_value = None
@@ -570,10 +593,18 @@
     return_value=(mock.sentinel.credentials, mock.sentinel.project),
 )
 def test_list_operations_rest(google_auth_default, credentials_file):
-    sync_transport = transports.rest.OperationsRestTransport(
-        credentials_file=credentials_file,
-        http_options=HTTP_OPTIONS,
-    )
+    if credentials_file:
+        with warn_deprecated_credentials_file():
+            sync_transport = transports.rest.OperationsRestTransport(
+                credentials_file=credentials_file,
+                http_options=HTTP_OPTIONS,
+            )
+    else:
+        # no warning expected
+        sync_transport = transports.rest.OperationsRestTransport(
+            credentials_file=credentials_file,
+            http_options=HTTP_OPTIONS,
+        )
 
     client = AbstractOperationsClient(transport=sync_transport)
 
@@ -1076,7 +1107,6 @@
     PYPARAM_CLIENT_TRANSPORT_CREDENTIALS,
 )
 def test_credentials_transport_error(client_class, transport_class, 
credentials):
-
     # It is an error to provide credentials and a transport instance.
     transport = transport_class(credentials=credentials)
     with pytest.raises(ValueError):
@@ -1130,10 +1160,11 @@
 def test_operations_base_transport_error():
     # Passing both a credentials object and credentials_file should raise an 
error
     with pytest.raises(core_exceptions.DuplicateCredentialArgs):
-        transports.OperationsTransport(
-            credentials=ga_credentials.AnonymousCredentials(),
-            credentials_file="credentials.json",
-        )
+        with warn_deprecated_credentials_file():
+            transports.OperationsTransport(
+                credentials=ga_credentials.AnonymousCredentials(),
+                credentials_file="credentials.json",
+            )
 
 
 def test_operations_base_transport():
@@ -1171,10 +1202,11 @@
     ) as Transport:
         Transport.return_value = None
         load_creds.return_value = (ga_credentials.AnonymousCredentials(), None)
-        transports.OperationsTransport(
-            credentials_file="credentials.json",
-            quota_project_id="octopus",
-        )
+        with warn_deprecated_credentials_file():
+            transports.OperationsTransport(
+                credentials_file="credentials.json",
+                quota_project_id="octopus",
+            )
         load_creds.assert_called_once_with(
             "credentials.json",
             scopes=None,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google_api_core-2.28.0/tests/unit/test_bidi.py 
new/google_api_core-2.29.0/tests/unit/test_bidi.py
--- old/google_api_core-2.28.0/tests/unit/test_bidi.py  2025-10-27 
23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/unit/test_bidi.py  2026-01-08 
23:08:42.000000000 +0100
@@ -301,10 +301,19 @@
         assert bidi_rpc._initial_request is None
         assert not bidi_rpc._callbacks
 
-    def test_close_no_rpc(self):
+    def test_close_with_no_rpc(self):
         bidi_rpc = bidi.BidiRpc(None)
         bidi_rpc.close()
 
+        assert bidi_rpc.call is None
+        assert bidi_rpc.is_active is False
+        # ensure the request queue was signaled to stop.
+        assert bidi_rpc.pending_requests == 1
+        assert bidi_rpc._request_queue.get() is None
+        # ensure request and callbacks are cleaned up
+        assert bidi_rpc._initial_request is None
+        assert not bidi_rpc._callbacks
+
     def test_send(self):
         rpc, call = make_rpc()
         bidi_rpc = bidi.BidiRpc(rpc)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/unit/test_client_logging.py 
new/google_api_core-2.29.0/tests/unit/test_client_logging.py
--- old/google_api_core-2.28.0/tests/unit/test_client_logging.py        
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/unit/test_client_logging.py        
2026-01-08 23:08:42.000000000 +0100
@@ -88,7 +88,6 @@
 
 
 def test_initialize_logging():
-
     with mock.patch("os.getenv", return_value="foogle.bar"):
         with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", 
"foogle"):
             initialize_logging()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/unit/test_client_options.py 
new/google_api_core-2.29.0/tests/unit/test_client_options.py
--- old/google_api_core-2.28.0/tests/unit/test_client_options.py        
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/unit/test_client_options.py        
2026-01-08 23:08:42.000000000 +0100
@@ -14,6 +14,7 @@
 
 from re import match
 import pytest
+from ..helpers import warn_deprecated_credentials_file
 
 from google.api_core import client_options
 
@@ -27,19 +28,19 @@
 
 
 def test_constructor():
-
-    options = client_options.ClientOptions(
-        api_endpoint="foo.googleapis.com",
-        client_cert_source=get_client_cert,
-        quota_project_id="quote-proj",
-        credentials_file="path/to/credentials.json",
-        scopes=[
-            "https://www.googleapis.com/auth/cloud-platform";,
-            "https://www.googleapis.com/auth/cloud-platform.read-only";,
-        ],
-        api_audience="foo2.googleapis.com",
-        universe_domain="googleapis.com",
-    )
+    with warn_deprecated_credentials_file():
+        options = client_options.ClientOptions(
+            api_endpoint="foo.googleapis.com",
+            client_cert_source=get_client_cert,
+            quota_project_id="quote-proj",
+            credentials_file="path/to/credentials.json",
+            scopes=[
+                "https://www.googleapis.com/auth/cloud-platform";,
+                "https://www.googleapis.com/auth/cloud-platform.read-only";,
+            ],
+            api_audience="foo2.googleapis.com",
+            universe_domain="googleapis.com",
+        )
 
     assert options.api_endpoint == "foo.googleapis.com"
     assert options.client_cert_source() == (b"cert", b"key")
@@ -54,7 +55,6 @@
 
 
 def test_constructor_with_encrypted_cert_source():
-
     options = client_options.ClientOptions(
         api_endpoint="foo.googleapis.com",
         client_encrypted_cert_source=get_client_encrypted_cert,
@@ -78,7 +78,6 @@
 
 
 def test_constructor_with_api_key():
-
     options = client_options.ClientOptions(
         api_endpoint="foo.googleapis.com",
         client_cert_source=get_client_cert,
@@ -102,10 +101,11 @@
 
 def test_constructor_with_both_api_key_and_credentials_file():
     with pytest.raises(ValueError):
-        client_options.ClientOptions(
-            api_key="api-key",
-            credentials_file="path/to/credentials.json",
-        )
+        with warn_deprecated_credentials_file():
+            client_options.ClientOptions(
+                api_key="api-key",
+                credentials_file="path/to/credentials.json",
+            )
 
 
 def test_from_dict():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/unit/test_grpc_helpers.py 
new/google_api_core-2.29.0/tests/unit/test_grpc_helpers.py
--- old/google_api_core-2.28.0/tests/unit/test_grpc_helpers.py  2025-10-27 
23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/unit/test_grpc_helpers.py  2026-01-08 
23:08:42.000000000 +0100
@@ -15,6 +15,7 @@
 from unittest import mock
 
 import pytest
+from ..helpers import warn_deprecated_credentials_file
 
 try:
     import grpc
@@ -581,11 +582,12 @@
     target = "example.com:443"
 
     with pytest.raises(exceptions.DuplicateCredentialArgs):
-        grpc_helpers.create_channel(
-            target,
-            credentials_file="credentials.json",
-            credentials=mock.sentinel.credentials,
-        )
+        with warn_deprecated_credentials_file():
+            grpc_helpers.create_channel(
+                target,
+                credentials_file="credentials.json",
+                credentials=mock.sentinel.credentials,
+            )
 
 
 @mock.patch("grpc.compute_engine_channel_credentials")
@@ -710,7 +712,8 @@
     credentials_file = "/path/to/credentials/file.json"
     composite_creds = composite_creds_call.return_value
 
-    channel = grpc_helpers.create_channel(target, 
credentials_file=credentials_file)
+    with warn_deprecated_credentials_file():
+        channel = grpc_helpers.create_channel(target, 
credentials_file=credentials_file)
 
     google.auth.load_credentials_from_file.assert_called_once_with(
         credentials_file, scopes=None, default_scopes=None
@@ -742,9 +745,10 @@
     credentials_file = "/path/to/credentials/file.json"
     composite_creds = composite_creds_call.return_value
 
-    channel = grpc_helpers.create_channel(
-        target, credentials_file=credentials_file, scopes=scopes
-    )
+    with warn_deprecated_credentials_file():
+        channel = grpc_helpers.create_channel(
+            target, credentials_file=credentials_file, scopes=scopes
+        )
 
     google.auth.load_credentials_from_file.assert_called_once_with(
         credentials_file, scopes=scopes, default_scopes=None
@@ -776,9 +780,10 @@
     credentials_file = "/path/to/credentials/file.json"
     composite_creds = composite_creds_call.return_value
 
-    channel = grpc_helpers.create_channel(
-        target, credentials_file=credentials_file, 
default_scopes=default_scopes
-    )
+    with warn_deprecated_credentials_file():
+        channel = grpc_helpers.create_channel(
+            target, credentials_file=credentials_file, 
default_scopes=default_scopes
+        )
 
     load_credentials_from_file.assert_called_once_with(
         credentials_file, scopes=None, default_scopes=default_scopes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/unit/test_page_iterator.py 
new/google_api_core-2.29.0/tests/unit/test_page_iterator.py
--- old/google_api_core-2.28.0/tests/unit/test_page_iterator.py 2025-10-27 
23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/unit/test_page_iterator.py 2026-01-08 
23:08:42.000000000 +0100
@@ -360,7 +360,6 @@
         assert iterator._has_next_page()
 
     def test__has_next_page_w_max_results_done(self):
-
         iterator = page_iterator.HTTPIterator(
             mock.sentinel.client,
             mock.sentinel.api_request,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/unit/test_python_package_support.py 
new/google_api_core-2.29.0/tests/unit/test_python_package_support.py
--- old/google_api_core-2.28.0/tests/unit/test_python_package_support.py        
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/unit/test_python_package_support.py        
2026-01-08 23:08:42.000000000 +0100
@@ -14,12 +14,12 @@
 
 import sys
 import warnings
-from unittest.mock import patch, MagicMock
+from unittest.mock import patch
 
 import pytest
-from packaging.version import parse as parse_version
 
 from google.api_core._python_package_support import (
+    parse_version_to_tuple,
     get_dependency_version,
     warn_deprecation_for_versions_less_than,
     check_dependency_versions,
@@ -28,39 +28,28 @@
 )
 
 
-# TODO(https://github.com/googleapis/python-api-core/issues/835): Remove
-# this mark once we drop support for Python 3.7
[email protected](sys.version_info < (3, 8), reason="requires python3.8 or 
higher")
-@patch("importlib.metadata.version")
-def test_get_dependency_version_py38_plus(mock_version):
-    """Test get_dependency_version on Python 3.8+."""
-    mock_version.return_value = "1.2.3"
-    expected = DependencyVersion(parse_version("1.2.3"), "1.2.3")
[email protected]("version_string_to_test", ["1.2.3", "1.2.3b1"])
+def test_get_dependency_version(mocker, version_string_to_test):
+    """Test get_dependency_version."""
+    if sys.version_info >= (3, 8):
+        mock_importlib = mocker.patch(
+            "importlib.metadata.version", return_value=version_string_to_test
+        )
+    else:
+        # TODO(https://github.com/googleapis/python-api-core/issues/835): 
Remove
+        # `importlib_metadata` once we drop support for Python 3.7
+        mock_importlib = mocker.patch(
+            "importlib_metadata.version", return_value=version_string_to_test
+        )
+    expected = DependencyVersion(
+        parse_version_to_tuple(version_string_to_test), version_string_to_test
+    )
     assert get_dependency_version("some-package") == expected
-    mock_version.assert_called_once_with("some-package")
-
-    # Test package not found
-    mock_version.side_effect = ImportError
-    assert get_dependency_version("not-a-package") == DependencyVersion(None, 
"--")
-
 
-# TODO(https://github.com/googleapis/python-api-core/issues/835): Remove
-# this test function once we drop support for Python 3.7
[email protected](sys.version_info >= (3, 8), reason="requires python3.7")
-@patch("pkg_resources.get_distribution")
-def test_get_dependency_version_py37(mock_get_distribution):
-    """Test get_dependency_version on Python 3.7."""
-    mock_dist = MagicMock()
-    mock_dist.version = "4.5.6"
-    mock_get_distribution.return_value = mock_dist
-    expected = DependencyVersion(parse_version("4.5.6"), "4.5.6")
-    assert get_dependency_version("another-package") == expected
-    mock_get_distribution.assert_called_once_with("another-package")
+    mock_importlib.assert_called_once_with("some-package")
 
     # Test package not found
-    mock_get_distribution.side_effect = (
-        Exception  # pkg_resources has its own exception types
-    )
+    mock_importlib.side_effect = ImportError
     assert get_dependency_version("not-a-package") == DependencyVersion(None, 
"--")
 
 
@@ -74,7 +63,9 @@
         ("my-package (my.package)", "my-package"),
     ]
 
-    mock_get_version.return_value = DependencyVersion(parse_version("1.0.0"), 
"1.0.0")
+    mock_get_version.return_value = DependencyVersion(
+        parse_version_to_tuple("1.0.0"), "1.0.0"
+    )
     with pytest.warns(FutureWarning) as record:
         warn_deprecation_for_versions_less_than("my.package", "dep.package", 
"2.0.0")
     assert len(record) == 1
@@ -90,14 +81,14 @@
         # Case 2: Installed version is equal to required, should not warn.
         mock_get_packages.reset_mock()
         mock_get_version.return_value = DependencyVersion(
-            parse_version("2.0.0"), "2.0.0"
+            parse_version_to_tuple("2.0.0"), "2.0.0"
         )
         warn_deprecation_for_versions_less_than("my.package", "dep.package", 
"2.0.0")
 
         # Case 3: Installed version is greater than required, should not warn.
         mock_get_packages.reset_mock()
         mock_get_version.return_value = DependencyVersion(
-            parse_version("3.0.0"), "3.0.0"
+            parse_version_to_tuple("3.0.0"), "3.0.0"
         )
         warn_deprecation_for_versions_less_than("my.package", "dep.package", 
"2.0.0")
 
@@ -115,7 +106,9 @@
         ("dep-package (dep.package)", "dep-package"),
         ("my-package (my.package)", "my-package"),
     ]
-    mock_get_version.return_value = DependencyVersion(parse_version("1.0.0"), 
"1.0.0")
+    mock_get_version.return_value = DependencyVersion(
+        parse_version_to_tuple("1.0.0"), "1.0.0"
+    )
     template = "Custom warning for {dependency_package} used by 
{consumer_package}."
     with pytest.warns(FutureWarning) as record:
         warn_deprecation_for_versions_less_than(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google_api_core-2.28.0/tests/unit/test_python_version_support.py 
new/google_api_core-2.29.0/tests/unit/test_python_version_support.py
--- old/google_api_core-2.28.0/tests/unit/test_python_version_support.py        
2025-10-27 23:37:20.000000000 +0100
+++ new/google_api_core-2.29.0/tests/unit/test_python_version_support.py        
2026-01-08 23:08:42.000000000 +0100
@@ -178,17 +178,20 @@
             "google.api_core._python_version_support.PYTHON_VERSION_INFO",
             {version_tuple: overridden_info},
         ):
-            result_before_boundary = check_python_version(
-                today=custom_gapic_end + datetime.timedelta(days=-1)
-            )
+            with pytest.warns(FutureWarning, match="past its end of life"):
+                result_before_boundary = check_python_version(
+                    today=custom_gapic_end + datetime.timedelta(days=-1)
+                )
             assert result_before_boundary == 
PythonVersionStatus.PYTHON_VERSION_EOL
 
-            result_at_boundary = check_python_version(today=custom_gapic_end)
+            with pytest.warns(FutureWarning, match="past its end of life"):
+                result_at_boundary = 
check_python_version(today=custom_gapic_end)
             assert result_at_boundary == PythonVersionStatus.PYTHON_VERSION_EOL
 
-            result_after_boundary = check_python_version(
-                today=custom_gapic_end + datetime.timedelta(days=1)
-            )
+            with pytest.warns(FutureWarning, match="non-supported Python 
version"):
+                result_after_boundary = check_python_version(
+                    today=custom_gapic_end + datetime.timedelta(days=1)
+                )
             assert (
                 result_after_boundary == 
PythonVersionStatus.PYTHON_VERSION_UNSUPPORTED
             )
@@ -217,7 +220,8 @@
                 result_before_boundary == 
PythonVersionStatus.PYTHON_VERSION_SUPPORTED
             )
 
-            result_at_boundary = check_python_version(today=custom_gapic_dep)
+            with pytest.warns(FutureWarning, match="Google will stop 
supporting"):
+                result_at_boundary = 
check_python_version(today=custom_gapic_dep)
             assert result_at_boundary == 
PythonVersionStatus.PYTHON_VERSION_DEPRECATED
 
 

Reply via email to