Skip to content

Commit b914cb8

Browse files
chore: remove Python 3.7 support (#1919)
Removing support for EOL Python 3.7. A warning was present in the README that support would be removed after January 2024 Also added a warning that Python 3.8 and 3.9 are also EOL, and will be removed in future updates --------- Co-authored-by: Victor Chudnovsky <vchudnov@google.com>
1 parent 5b01d94 commit b914cb8

File tree

9 files changed

+101
-62
lines changed

9 files changed

+101
-62
lines changed

packages/google-auth/CONTRIBUTING.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ A few notes on making changes to ``google-auth-library-python``.
1919
using ``nox -s docs``.
2020

2121
- The change must work fully on the following CPython versions:
22-
3.7, 3.8, 3.9, 3.10, 3.11, 3.12 and 3.13 across macOS, Linux, and Windows.
22+
3.8, 3.9, 3.10, 3.11, 3.12, 3.13 and 3.14 across macOS, Linux, and Windows.
2323

2424
- The codebase *must* have 100% test statement coverage after each commit.
2525
You can test coverage via ``nox -e cover``.

packages/google-auth/README.rst

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,16 @@ Note that the extras pyopenssl and enterprise_cert should not be used together b
3535

3636
Supported Python Versions
3737
^^^^^^^^^^^^^^^^^^^^^^^^^
38-
Python >= 3.7
38+
Python >= 3.8
3939

4040
**NOTE**:
41-
Python 3.7 was marked as `unsupported`_ by the python community in June 2023.
42-
We recommend that all developers upgrade to Python 3.8 and newer as soon as
43-
they can. Support for Python 3.7 will be removed from this library after
44-
January 1 2024. Previous releases that support Python 3.7 will continue to be available
45-
for download, but releases after January 1 2024 will only target Python 3.8 and
46-
newer.
41+
Python 3.8 and Python 3.9 were marked as `unsupported`_ by the python community in
42+
October 2024 and October 2025, respectively.
43+
We recommend that all developers upgrade to Python 3.10 and newer as soon as
44+
they can. Support for end-of-life Python runtimes will be removed from this
45+
library in future updates.
46+
Previous releases that support end-of-life Python versions will continue to be available
47+
for download, but future releases will only target supported versions.
4748

4849
.. _unsupported: https://devguide.python.org/versions/#unsupported-versions
4950

@@ -58,6 +59,10 @@ Unsupported Python Versions
5859
- Python 3.6: The last version of this library with support for Python 3.6
5960
was `google.auth == 2.22.0`.
6061

62+
- Python 3.7: The last version of this library with support for Python 3.7
63+
was `google.auth == 2.45.0`.
64+
65+
6166
Documentation
6267
-------------
6368

packages/google-auth/google/auth/__init__.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,17 @@ class Python37DeprecationWarning(DeprecationWarning): # pragma: NO COVER
4141
pass
4242

4343

44-
# Checks if the current runtime is Python 3.7.
45-
if sys.version_info.major == 3 and sys.version_info.minor == 7: # pragma: NO COVER
46-
message = (
47-
"After January 1, 2024, new releases of this library will drop support "
48-
"for Python 3.7."
49-
)
50-
warnings.warn(message, Python37DeprecationWarning)
44+
# Raise warnings for deprecated versions
45+
eol_message = """
46+
You are using a Python version {} past its end of life. Google will update
47+
google-auth with critical bug fixes on a best-effort basis, but not
48+
with any other fixes or features. Please upgrade your Python version,
49+
and then update google-auth.
50+
"""
51+
if sys.version_info.major == 3 and sys.version_info.minor == 8: # pragma: NO COVER
52+
warnings.warn(eol_message.format("3.8"), FutureWarning)
53+
elif sys.version_info.major == 3 and sys.version_info.minor == 9: # pragma: NO COVER
54+
warnings.warn(eol_message.format("3.9"), FutureWarning)
5155

5256
# Set default logging handler to avoid "No handler found" warnings.
5357
logging.getLogger(__name__).addHandler(logging.NullHandler())

packages/google-auth/google/auth/_helpers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ def is_python_3():
334334
Returns:
335335
bool: True if the Python interpreter is Python 3 and False otherwise.
336336
"""
337-
return sys.version_info > (3, 0)
337+
338+
return sys.version_info > (3, 0) # pragma: NO COVER
338339

339340

340341
def _hash_sensitive_info(data: Union[dict, list]) -> Union[dict, list, str]:

packages/google-auth/google/auth/pluggable.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,6 @@ def retrieve_subject_token(self, request):
201201
else:
202202
return subject_token
203203

204-
if not _helpers.is_python_3():
205-
raise exceptions.RefreshError(
206-
"Pluggable auth is only supported for python 3.7+"
207-
)
208-
209204
# Inject env vars.
210205
env = os.environ.copy()
211206
self._inject_env_variables(env)
@@ -263,11 +258,6 @@ def revoke(self, request):
263258
)
264259
self._validate_running_mode()
265260

266-
if not _helpers.is_python_3():
267-
raise exceptions.RefreshError(
268-
"Pluggable auth is only supported for python 3.7+"
269-
)
270-
271261
# Inject variables
272262
env = os.environ.copy()
273263
self._inject_env_variables(env)

packages/google-auth/google/oauth2/__init__.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,14 @@ class Python37DeprecationWarning(DeprecationWarning): # pragma: NO COVER
2727
pass
2828

2929

30-
# Checks if the current runtime is Python 3.7.
31-
if sys.version_info.major == 3 and sys.version_info.minor == 7: # pragma: NO COVER
32-
message = (
33-
"After January 1, 2024, new releases of this library will drop support "
34-
"for Python 3.7."
35-
)
36-
warnings.warn(message, Python37DeprecationWarning)
30+
# Raise warnings for deprecated versions
31+
eol_message = """
32+
You are using a Python version {} past its end of life. Google will update
33+
google-auth with critical bug fixes on a best-effort basis, but not
34+
with any other fixes or features. Please upgrade your Python version,
35+
and then update google-auth.
36+
"""
37+
if sys.version_info.major == 3 and sys.version_info.minor == 8: # pragma: NO COVER
38+
warnings.warn(eol_message.format("3.8"), FutureWarning)
39+
elif sys.version_info.major == 3 and sys.version_info.minor == 9: # pragma: NO COVER
40+
warnings.warn(eol_message.format("3.9"), FutureWarning)

packages/google-auth/setup.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,8 @@
2626
"rsa>=3.1.4,<5",
2727
)
2828

29-
# TODO(https://github.com/googleapis/google-auth-library-python/issues/1737): Unit test fails with
30-
# `No module named 'cryptography.hazmat.backends.openssl.x509' for Python 3.7``.
3129
cryptography_base_require = [
3230
"cryptography >= 38.0.3",
33-
"cryptography < 39.0.0; python_version < '3.8'",
3431
]
3532

3633
requests_extra_require = ["requests >= 2.20.0, < 3.0.0"]
@@ -116,12 +113,11 @@
116113
package_data={"google.auth": ["py.typed"], "google.oauth2": ["py.typed"]},
117114
install_requires=DEPENDENCIES,
118115
extras_require=extras,
119-
python_requires=">=3.7",
116+
python_requires=">=3.8",
120117
license="Apache 2.0",
121118
keywords="google auth oauth client",
122119
classifiers=[
123120
"Programming Language :: Python :: 3",
124-
"Programming Language :: Python :: 3.7",
125121
"Programming Language :: Python :: 3.8",
126122
"Programming Language :: Python :: 3.9",
127123
"Programming Language :: Python :: 3.10",

packages/google-auth/tests/test_pluggable.py

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,16 +1230,6 @@ def test_revoke_successfully(self):
12301230
)
12311231
_ = credentials.revoke(None)
12321232

1233-
@mock.patch.dict(os.environ, {"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
1234-
def test_retrieve_subject_token_python_2(self):
1235-
with mock.patch("sys.version_info", (2, 7)):
1236-
credentials = self.make_pluggable(credential_source=self.CREDENTIAL_SOURCE)
1237-
1238-
with pytest.raises(exceptions.RefreshError) as excinfo:
1239-
_ = credentials.retrieve_subject_token(None)
1240-
1241-
assert excinfo.match(r"Pluggable auth is only supported for python 3.7+")
1242-
12431233
@mock.patch.dict(os.environ, {"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
12441234
def test_retrieve_subject_token_with_quoted_command(self):
12451235
command_with_spaces = '"/path/with spaces/to/executable" "arg with spaces"'
@@ -1269,17 +1259,3 @@ def test_retrieve_subject_token_with_quoted_command(self):
12691259
stderr=subprocess.STDOUT,
12701260
env=mock.ANY,
12711261
)
1272-
1273-
@mock.patch.dict(os.environ, {"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"})
1274-
def test_revoke_subject_token_python_2(self):
1275-
with mock.patch("sys.version_info", (2, 7)):
1276-
credentials = self.make_pluggable(
1277-
audience=WORKFORCE_AUDIENCE,
1278-
credential_source=self.CREDENTIAL_SOURCE,
1279-
interactive=True,
1280-
)
1281-
1282-
with pytest.raises(exceptions.RefreshError) as excinfo:
1283-
_ = credentials.revoke(None)
1284-
1285-
assert excinfo.match(r"Pluggable auth is only supported for python 3.7+")
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import importlib
16+
import sys
17+
from unittest import mock
18+
import warnings
19+
20+
import pytest
21+
22+
import google.auth
23+
import google.oauth2
24+
25+
26+
@pytest.mark.parametrize("module", [google.auth, google.oauth2])
27+
@pytest.mark.parametrize(
28+
"version, expected_warning",
29+
[
30+
((3, 8), True),
31+
((3, 9), True),
32+
((3, 10), False),
33+
((3, 13), False),
34+
],
35+
)
36+
def test_python_version_warnings(module, version, expected_warning):
37+
# Mock sys.version_info
38+
# We use a MagicMock that has major and minor attributes
39+
mock_version = mock.Mock()
40+
mock_version.major = version[0]
41+
mock_version.minor = version[1]
42+
43+
with mock.patch.object(sys, "version_info", mock_version):
44+
with warnings.catch_warnings(record=True) as caught_warnings:
45+
warnings.simplefilter("always")
46+
importlib.reload(module)
47+
48+
future_warnings = [
49+
w
50+
for w in caught_warnings
51+
if issubclass(w.category, FutureWarning)
52+
and "past its end of life" in str(w.message)
53+
]
54+
55+
if expected_warning:
56+
assert (
57+
len(future_warnings) > 0
58+
), f"Expected FutureWarning for Python {version} in {module.__name__}"
59+
assert str(version[1]) in str(future_warnings[0].message)
60+
else:
61+
assert (
62+
len(future_warnings) == 0
63+
), f"Did not expect FutureWarning for Python {version} in {module.__name__}"

0 commit comments

Comments
 (0)