Skip to content
This repository was archived by the owner on Mar 6, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
250f015
chore: replace deprecated utcfromtimestamp
andriawang6 Jul 30, 2025
0181b9c
Merge branch 'main' into replace-utcfromtimestamp
gkevinzheng Dec 17, 2025
56c135a
Merge branch 'main' into replace-utcfromtimestamp
gkevinzheng Dec 18, 2025
f0cd184
Merge branch 'main' into replace-utcfromtimestamp
chalmerlowe Dec 29, 2025
16616cc
fix: updates with helper function for utcfromtimestamp
chalmerlowe Dec 29, 2025
e186d3f
fix: remove unneeded import
chalmerlowe Dec 29, 2025
0da5e38
fix: update blank line
chalmerlowe Dec 29, 2025
4109407
fix: restore accidently deleted import: copy
chalmerlowe Dec 29, 2025
93a2c67
fix: remove unneeded import: datetime
chalmerlowe Dec 29, 2025
83371b2
updates tests and imports
chalmerlowe Dec 29, 2025
c8b2a84
Merge branch 'main' into replace-utcfromtimestamp
chalmerlowe Dec 29, 2025
ff5ea3c
test: adds unittests for utcfromtimestamp
chalmerlowe Dec 30, 2025
5ec7842
Merge branch 'main' into replace-utcfromtimestamp
chalmerlowe Dec 30, 2025
842ba17
fix: adds specific errortype to pytest.raises statement
chalmerlowe Dec 30, 2025
9f5f6ae
fix: update linting in test__helpers.py
chalmerlowe Dec 30, 2025
93fdf1b
updates formatting to satisfy linting
chalmerlowe Dec 30, 2025
c46d482
Merge branch 'main' into replace-utcfromtimestamp
chalmerlowe Jan 5, 2026
4d552d1
reverts back in order to remove unneeded mods to test_client_async.py
chalmerlowe Jan 5, 2026
3cd7e3d
ensures that the new helper is used universally
chalmerlowe Jan 5, 2026
098fddc
Merge branch 'main' into replace-utcfromtimestamp
chalmerlowe Jan 5, 2026
c08a16d
Merge branch 'main' into replace-utcfromtimestamp
chalmerlowe Jan 7, 2026
d501661
Merge branch 'main' into replace-utcfromtimestamp
chalmerlowe Jan 8, 2026
47555de
removes updates accidnetally added during experimentation and testing…
chalmerlowe Jan 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion google/auth/app_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def refresh(self, request):
scopes = self._scopes if self._scopes is not None else self._default_scopes
# pylint: disable=unused-argument
token, ttl = app_identity.get_access_token(scopes, self._service_account_id)
expiry = datetime.datetime.utcfromtimestamp(ttl)
expiry = datetime.datetime.fromtimestamp(ttl, tz=datetime.timezone.utc)

self.token, self.expiry = token, expiry

Expand Down
2 changes: 1 addition & 1 deletion google/auth/compute_engine/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ def _call_metadata_identity_endpoint(self, request):
raise new_exc from caught_exc

_, payload, _, _ = jwt._unverified_decode(id_token)
return id_token, datetime.datetime.utcfromtimestamp(payload["exp"])
return id_token, datetime.datetime.fromtimestamp(payload["exp"], tz=datetime.timezone.utc)

def refresh(self, request):
"""Refreshes the ID token.
Expand Down
6 changes: 3 additions & 3 deletions google/auth/impersonated_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

import base64
import copy
from datetime import datetime
from datetime import datetime, timezone
import http.client as http_client
import json

Expand Down Expand Up @@ -649,8 +649,8 @@ def refresh(self, request):
raise new_exc from caught_exc

self.token = id_token
self.expiry = datetime.utcfromtimestamp(
jwt.decode(id_token, verify=False)["exp"]
self.expiry = datetime.fromtimestamp(
jwt.decode(id_token, verify=False)["exp"], tz=timezone.utc
)


Expand Down
4 changes: 2 additions & 2 deletions google/oauth2/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ def call_iam_generate_id_token_endpoint(
raise new_exc from caught_exc

payload = jwt.decode(id_token, verify=False)
expiry = datetime.datetime.utcfromtimestamp(payload["exp"])
expiry = datetime.datetime.fromtimestamp(payload["exp"], tz=datetime.timezone.utc)

return id_token, expiry

Expand Down Expand Up @@ -420,7 +420,7 @@ def id_token_jwt_grant(request, token_uri, assertion, can_retry=True):
raise new_exc from caught_exc

payload = jwt.decode(id_token, verify=False)
expiry = datetime.datetime.utcfromtimestamp(payload["exp"])
expiry = datetime.datetime.fromtimestamp(payload["exp"], tz=datetime.timezone.utc)

return id_token, expiry, response_data

Expand Down
2 changes: 1 addition & 1 deletion google/oauth2/_client_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ async def id_token_jwt_grant(request, token_uri, assertion, can_retry=True):
raise new_exc from caught_exc

payload = jwt.decode(id_token, verify=False)
expiry = datetime.datetime.utcfromtimestamp(payload["exp"])
expiry = datetime.datetime.fromtimestamp(payload["exp"], tz=datetime.timezone.utc)

return id_token, expiry, response_data

Expand Down
28 changes: 14 additions & 14 deletions tests/compute_engine/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ def test_default_state(self, get):

@mock.patch(
"google.auth._helpers.utcnow",
return_value=datetime.datetime.utcfromtimestamp(0),
return_value=datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc),
)
@mock.patch("google.auth.compute_engine._metadata.get", autospec=True)
@mock.patch("google.auth.iam.Signer.sign", autospec=True)
Expand Down Expand Up @@ -791,7 +791,7 @@ def test_make_authorization_grant_assertion(self, sign, get, utcnow):

@mock.patch(
"google.auth._helpers.utcnow",
return_value=datetime.datetime.utcfromtimestamp(0),
return_value=datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc),
)
@mock.patch("google.auth.compute_engine._metadata.get", autospec=True)
@mock.patch("google.auth.iam.Signer.sign", autospec=True)
Expand Down Expand Up @@ -823,7 +823,7 @@ def test_with_service_account(self, sign, get, utcnow):

@mock.patch(
"google.auth._helpers.utcnow",
return_value=datetime.datetime.utcfromtimestamp(0),
return_value=datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc),
)
@mock.patch("google.auth.compute_engine._metadata.get", autospec=True)
@mock.patch("google.auth.iam.Signer.sign", autospec=True)
Expand Down Expand Up @@ -879,7 +879,7 @@ def test_token_uri(self):

@mock.patch(
"google.auth._helpers.utcnow",
return_value=datetime.datetime.utcfromtimestamp(0),
return_value=datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc),
)
@mock.patch("google.auth.compute_engine._metadata.get", autospec=True)
@mock.patch("google.auth.iam.Signer.sign", autospec=True)
Expand Down Expand Up @@ -1001,7 +1001,7 @@ def test_with_target_audience_integration(self):

@mock.patch(
"google.auth._helpers.utcnow",
return_value=datetime.datetime.utcfromtimestamp(0),
return_value=datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc),
)
@mock.patch("google.auth.compute_engine._metadata.get", autospec=True)
@mock.patch("google.auth.iam.Signer.sign", autospec=True)
Expand Down Expand Up @@ -1040,7 +1040,7 @@ def test_with_quota_project(self, sign, get, utcnow):

@mock.patch(
"google.auth._helpers.utcnow",
return_value=datetime.datetime.utcfromtimestamp(0),
return_value=datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc),
)
@mock.patch("google.auth.compute_engine._metadata.get", autospec=True)
@mock.patch("google.auth.iam.Signer.sign", autospec=True)
Expand All @@ -1062,7 +1062,7 @@ def test_with_token_uri(self, sign, get, utcnow):

@mock.patch(
"google.auth._helpers.utcnow",
return_value=datetime.datetime.utcfromtimestamp(0),
return_value=datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc),
)
@mock.patch("google.auth.compute_engine._metadata.get", autospec=True)
@mock.patch("google.auth.iam.Signer.sign", autospec=True)
Expand Down Expand Up @@ -1170,7 +1170,7 @@ def test_with_quota_project_integration(self):

@mock.patch(
"google.auth._helpers.utcnow",
return_value=datetime.datetime.utcfromtimestamp(0),
return_value=datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc),
)
@mock.patch("google.auth.compute_engine._metadata.get", autospec=True)
@mock.patch("google.auth.iam.Signer.sign", autospec=True)
Expand All @@ -1181,7 +1181,7 @@ def test_refresh_success(self, id_token_jwt_grant, sign, get, utcnow):
]
sign.side_effect = [b"signature"]
id_token_jwt_grant.side_effect = [
("idtoken", datetime.datetime.utcfromtimestamp(3600), {})
("idtoken", datetime.datetime.fromtimestamp(3600, tz=datetime.timezone.utc), {})
]

request = mock.create_autospec(transport.Request, instance=True)
Expand All @@ -1194,7 +1194,7 @@ def test_refresh_success(self, id_token_jwt_grant, sign, get, utcnow):

# Check that the credentials have the token and proper expiration
assert self.credentials.token == "idtoken"
assert self.credentials.expiry == (datetime.datetime.utcfromtimestamp(3600))
assert self.credentials.expiry == (datetime.datetime.fromtimestamp(3600, tz=datetime.timezone.utc))

# Check the credential info
assert self.credentials.service_account_email == "service-account@example.com"
Expand All @@ -1205,7 +1205,7 @@ def test_refresh_success(self, id_token_jwt_grant, sign, get, utcnow):

@mock.patch(
"google.auth._helpers.utcnow",
return_value=datetime.datetime.utcfromtimestamp(0),
return_value=datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc),
)
@mock.patch("google.auth.compute_engine._metadata.get", autospec=True)
@mock.patch("google.auth.iam.Signer.sign", autospec=True)
Expand All @@ -1232,7 +1232,7 @@ def test_refresh_error(self, sign, get, utcnow):

@mock.patch(
"google.auth._helpers.utcnow",
return_value=datetime.datetime.utcfromtimestamp(0),
return_value=datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use _helpers.utcfromtimestamp . Applies throughout

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved.

)
@mock.patch("google.auth.compute_engine._metadata.get", autospec=True)
@mock.patch("google.auth.iam.Signer.sign", autospec=True)
Expand All @@ -1243,7 +1243,7 @@ def test_before_request_refreshes(self, id_token_jwt_grant, sign, get, utcnow):
]
sign.side_effect = [b"signature"]
id_token_jwt_grant.side_effect = [
("idtoken", datetime.datetime.utcfromtimestamp(3600), {})
("idtoken", datetime.datetime.fromtimestamp(3600, tz=datetime.timezone.utc), {})
]

request = mock.create_autospec(transport.Request, instance=True)
Expand Down Expand Up @@ -1312,7 +1312,7 @@ def test_get_id_token_from_metadata(
}

assert cred.token == SAMPLE_ID_TOKEN
assert cred.expiry == datetime.datetime.utcfromtimestamp(SAMPLE_ID_TOKEN_EXP)
assert cred.expiry == datetime.datetime.fromtimestamp(SAMPLE_ID_TOKEN_EXP, tz=datetime.timezone.utc)
assert cred._use_metadata_identity_endpoint
assert cred._signer is None
assert cred._token_uri is None
Expand Down
8 changes: 4 additions & 4 deletions tests/oauth2/test__client.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ def test_jwt_grant_no_access_token():


def test_call_iam_generate_id_token_endpoint():
now = _helpers.utcnow()
now = _helpers.utcnow().astimezone(datetime.timezone.utc)
Copy link
Copy Markdown
Contributor

@parthea parthea Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests pass without the changes to tests/oauth2/test__client.py . Let's revert all of the changes in tests/oauth2/test__client.py

id_token_expiry = _helpers.datetime_to_secs(now)
id_token = jwt.encode(SIGNER, {"exp": id_token_expiry}).decode("utf-8")
request = make_request({"token": id_token})
Expand Down Expand Up @@ -343,7 +343,7 @@ def test_call_iam_generate_id_token_endpoint():
# Check result
assert token == id_token
# JWT does not store microseconds
now = now.replace(microsecond=0)
now = now.replace(microsecond=0).astimezone(datetime.timezone.utc)
assert expiry == now


Expand All @@ -368,7 +368,7 @@ def test_call_iam_generate_id_token_endpoint_no_id_token():


def test_id_token_jwt_grant():
now = _helpers.utcnow()
now = _helpers.utcnow().astimezone(datetime.timezone.utc)
id_token_expiry = _helpers.datetime_to_secs(now)
id_token = jwt.encode(SIGNER, {"exp": id_token_expiry}).decode("utf-8")
request = make_request({"id_token": id_token, "extra": "data"})
Expand All @@ -385,7 +385,7 @@ def test_id_token_jwt_grant():
# Check result
assert token == id_token
# JWT does not store microseconds
now = now.replace(microsecond=0)
now = now.replace(microsecond=0).astimezone(datetime.timezone.utc)
assert expiry == now
assert extra_data["extra"] == "data"

Expand Down
8 changes: 4 additions & 4 deletions tests/test_app_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def test_service_account_email_explicit(self, app_identity):
assert credentials.service_account_email == mock.sentinel.service_account_email
assert not app_identity.get_service_account_name.called

@mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min)
@mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min.replace(tzinfo=datetime.timezone.utc))
def test_refresh(self, utcnow, app_identity):
token = "token"
ttl = 643942923
Expand All @@ -174,11 +174,11 @@ def test_refresh(self, utcnow, app_identity):
credentials.scopes, credentials._service_account_id
)
assert credentials.token == token
assert credentials.expiry == datetime.datetime(1990, 5, 29, 1, 2, 3)
assert credentials.expiry == datetime.datetime(1990, 5, 29, 1, 2, 3, tzinfo=datetime.timezone.utc)
assert credentials.valid
assert not credentials.expired

@mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min)
@mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min.replace(tzinfo=datetime.timezone.utc))
def test_refresh_with_default_scopes(self, utcnow, app_identity):
token = "token"
ttl = 643942923
Expand All @@ -191,7 +191,7 @@ def test_refresh_with_default_scopes(self, utcnow, app_identity):
credentials.default_scopes, credentials._service_account_id
)
assert credentials.token == token
assert credentials.expiry == datetime.datetime(1990, 5, 29, 1, 2, 3)
assert credentials.expiry == datetime.datetime(1990, 5, 29, 1, 2, 3, tzinfo=datetime.timezone.utc)
assert credentials.valid
assert not credentials.expired

Expand Down
8 changes: 4 additions & 4 deletions tests/test_impersonated_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -1046,7 +1046,7 @@ def test_id_token_success(
id_creds.refresh(request)

assert id_creds.token == ID_TOKEN_DATA
assert id_creds.expiry == datetime.datetime.utcfromtimestamp(ID_TOKEN_EXPIRY)
assert id_creds.expiry == datetime.datetime.fromtimestamp(ID_TOKEN_EXPIRY, tz=datetime.timezone.utc)

def test_id_token_metrics(self, mock_donor_credentials):
credentials = self.make_credentials(lifetime=None)
Expand All @@ -1070,8 +1070,8 @@ def test_id_token_metrics(self, mock_donor_credentials):
id_creds.refresh(None)

assert id_creds.token == ID_TOKEN_DATA
assert id_creds.expiry == datetime.datetime.utcfromtimestamp(
ID_TOKEN_EXPIRY
assert id_creds.expiry == datetime.datetime.fromtimestamp(
ID_TOKEN_EXPIRY, tz=datetime.timezone.utc
)
assert (
mock_post.call_args.kwargs["headers"]["x-goog-api-client"]
Expand Down Expand Up @@ -1180,7 +1180,7 @@ def test_id_token_with_target_audience(
id_creds.refresh(request)

assert id_creds.token == ID_TOKEN_DATA
assert id_creds.expiry == datetime.datetime.utcfromtimestamp(ID_TOKEN_EXPIRY)
assert id_creds.expiry == datetime.datetime.fromtimestamp(ID_TOKEN_EXPIRY, tz=datetime.timezone.utc)
assert id_creds._include_email is True

def test_id_token_invalid_cred(
Expand Down
4 changes: 2 additions & 2 deletions tests_async/oauth2/test__client_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ async def test_jwt_grant_no_access_token():

@pytest.mark.asyncio
async def test_id_token_jwt_grant():
now = _helpers.utcnow()
now = _helpers.utcnow().astimezone(datetime.timezone.utc)
id_token_expiry = _helpers.datetime_to_secs(now)
id_token = jwt.encode(test_client.SIGNER, {"exp": id_token_expiry}).decode("utf-8")
request = make_request({"id_token": id_token, "extra": "data"})
Expand All @@ -260,7 +260,7 @@ async def test_id_token_jwt_grant():
# Check result
assert token == id_token
# JWT does not store microseconds
now = now.replace(microsecond=0)
now = now.replace(microsecond=0).astimezone(datetime.timezone.utc)
assert expiry == now
assert extra_data["extra"] == "data"

Expand Down
Loading