Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve Python 3.12 .utcnow() DeprecationWarning #3239

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 9 additions & 3 deletions botocore/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,9 @@ def signature(self, string_to_sign, request):
def add_auth(self, request):
if self.credentials is None:
raise NoCredentialsError()
datetime_now = datetime.datetime.utcnow()
datetime_now = datetime.datetime.now(datetime.timezone.utc).replace(
tzinfo=None
)
request.context['timestamp'] = datetime_now.strftime(SIGV4_TIMESTAMP)
# This could be a retry. Make sure the previous
# authorization header is removed first.
Expand Down Expand Up @@ -559,7 +561,9 @@ class S3ExpressPostAuth(S3ExpressAuth):
REQUIRES_IDENTITY_CACHE = True

def add_auth(self, request):
datetime_now = datetime.datetime.utcnow()
datetime_now = datetime.datetime.now(datetime.timezone.utc).replace(
tzinfo=None
)
request.context['timestamp'] = datetime_now.strftime(SIGV4_TIMESTAMP)

fields = {}
Expand Down Expand Up @@ -818,7 +822,9 @@ class S3SigV4PostAuth(SigV4Auth):
"""

def add_auth(self, request):
datetime_now = datetime.datetime.utcnow()
datetime_now = datetime.datetime.now(datetime.timezone.utc).replace(
tzinfo=None
)
request.context['timestamp'] = datetime_now.strftime(SIGV4_TIMESTAMP)

fields = {}
Expand Down
12 changes: 2 additions & 10 deletions botocore/crt/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,7 @@ def add_auth(self, request):
if self.credentials is None:
raise NoCredentialsError()

# Use utcnow() because that's what gets mocked by tests, but set
# timezone because CRT assumes naive datetime is local time.
datetime_now = datetime.datetime.utcnow().replace(
tzinfo=datetime.timezone.utc
)
datetime_now = datetime.datetime.now(datetime.timezone.utc)

# Use existing 'X-Amz-Content-SHA256' header if able
existing_sha256 = self._get_existing_sha256(request)
Expand Down Expand Up @@ -251,11 +247,7 @@ def add_auth(self, request):
if self.credentials is None:
raise NoCredentialsError()

# Use utcnow() because that's what gets mocked by tests, but set
# timezone because CRT assumes naive datetime is local time.
datetime_now = datetime.datetime.utcnow().replace(
tzinfo=datetime.timezone.utc
)
datetime_now = datetime.datetime.now(datetime.timezone.utc)

# Use existing 'X-Amz-Content-SHA256' header if able
existing_sha256 = self._get_existing_sha256(request)
Expand Down
8 changes: 6 additions & 2 deletions botocore/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ def prepare_request(self, request):
def _calculate_ttl(
self, response_received_timestamp, date_header, read_timeout
):
local_timestamp = datetime.datetime.utcnow()
local_timestamp = datetime.datetime.now(datetime.timezone.utc).replace(
tzinfo=None
)
date_conversion = datetime.datetime.strptime(
date_header, "%a, %d %b %Y %H:%M:%S %Z"
)
Expand All @@ -167,7 +169,9 @@ def _set_ttl(self, retries_context, read_timeout, success_response):
has_streaming_input = retries_context.get('has_streaming_input')
if response_date_header and not has_streaming_input:
try:
response_received_timestamp = datetime.datetime.utcnow()
response_received_timestamp = datetime.datetime.now(
datetime.timezone.utc
).replace(tzinfo=None)
retries_context['ttl'] = self._calculate_ttl(
response_received_timestamp,
response_date_header,
Expand Down
4 changes: 3 additions & 1 deletion botocore/signers.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,9 @@ def generate_presigned_post(
policy = {}

# Create an expiration date for the policy
datetime_now = datetime.datetime.utcnow()
datetime_now = datetime.datetime.now(datetime.timezone.utc).replace(
tzinfo=None
)
expire_date = datetime_now + datetime.timedelta(seconds=expires_in)
policy['expiration'] = expire_date.strftime(botocore.auth.ISO8601)

Expand Down
4 changes: 3 additions & 1 deletion botocore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,9 @@ def _evaluate_expiration(self, credentials):
)
jitter = random.randint(120, 600) # Between 2 to 10 minutes
refresh_interval_with_jitter = refresh_interval + jitter
current_time = datetime.datetime.utcnow()
current_time = datetime.datetime.now(
datetime.timezone.utc
).replace(tzinfo=None)
refresh_offset = datetime.timedelta(
seconds=refresh_interval_with_jitter
)
Expand Down
8 changes: 5 additions & 3 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,20 +567,22 @@ class FreezeTime(ContextDecorator):
:param module: reference to imported module to patch (e.g. botocore.auth.datetime)

:type date: datetime.datetime
:param date: datetime object specifying the output for utcnow()
:param date: datetime object specifying the output for now()
"""

def __init__(self, module, date=None):
if date is None:
date = datetime.datetime.utcnow()
date = datetime.datetime.now(datetime.timezone.utc).replace(
tzinfo=None
)
self.date = date
self.datetime_patcher = mock.patch.object(
module, 'datetime', mock.Mock(wraps=datetime.datetime)
)

def __enter__(self, *args, **kwargs):
mock = self.datetime_patcher.start()
mock.utcnow.return_value = self.date
mock.now.return_value = self.date

def __exit__(self, *args, **kwargs):
self.datetime_patcher.stop()
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/test_ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def setUp(self):
mock.Mock(wraps=datetime.datetime),
)
self.mocked_datetime = self.datetime_patch.start()
self.mocked_datetime.utcnow.return_value = self.now
self.mocked_datetime.now.return_value = self.now

def tearDown(self):
super().tearDown()
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/test_lex.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def test_unsigned_payload(self):
timestamp = datetime(2017, 3, 22, 0, 0)

with mock.patch('botocore.auth.datetime.datetime') as _datetime:
_datetime.utcnow.return_value = timestamp
_datetime.now.return_value = timestamp
self.http_stubber.add_response(body=b'{}')
with self.http_stubber:
self.client.post_content(**params)
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/test_retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def _test_amz_sdk_request_header_with_test_case(
mock.Mock(wraps=datetime.datetime),
)
mocked_datetime = datetime_patcher.start()
mocked_datetime.utcnow.side_effect = utcnow_side_effects
mocked_datetime.now.side_effect = utcnow_side_effects

client = self.session.create_client(
'dynamodb', self.region, config=client_config
Expand Down
8 changes: 1 addition & 7 deletions tests/functional/test_s3express.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ def test_s3_express_auth_headers(self):
class TestS3ExpressIdentityCache:
def test_default_s3_express_cache(self, default_s3_client, mock_datetime):
mock_datetime.now.return_value = DATE
mock_datetime.utcnow.return_value = DATE

identity_cache = S3ExpressIdentityCache(
default_s3_client,
Expand All @@ -126,7 +125,6 @@ def test_s3_express_cache_one_network_call(
self, default_s3_client, mock_datetime
):
mock_datetime.now.return_value = DATE
mock_datetime.utcnow.return_value = DATE
bucket = 'my_bucket'

identity_cache = S3ExpressIdentityCache(
Expand All @@ -151,7 +149,6 @@ def test_s3_express_cache_multiple_buckets(
self, default_s3_client, mock_datetime
):
mock_datetime.now.return_value = DATE
mock_datetime.utcnow.return_value = DATE
bucket = 'my_bucket'
other_bucket = 'other_bucket'

Expand Down Expand Up @@ -204,7 +201,7 @@ def _call_get_object(self, client):
)

def test_create_bucket(self, default_s3_client, mock_datetime):
mock_datetime.utcnow.return_value = DATE
mock_datetime.now.return_value = DATE

with ClientHTTPStubber(default_s3_client) as stubber:
stubber.add_response()
Expand All @@ -228,7 +225,6 @@ def test_create_bucket(self, default_s3_client, mock_datetime):
self._assert_standard_sigv4_signature(stubber.requests[0].headers)

def test_get_object(self, default_s3_client, mock_datetime):
mock_datetime.utcnow.return_value = DATE
mock_datetime.now.return_value = DATE

with ClientHTTPStubber(default_s3_client) as stubber:
Expand All @@ -250,7 +246,6 @@ def test_get_object(self, default_s3_client, mock_datetime):
def test_cache_with_multiple_requests(
self, default_s3_client, mock_datetime
):
mock_datetime.utcnow.return_value = DATE
mock_datetime.now.return_value = DATE

with ClientHTTPStubber(default_s3_client) as stubber:
Expand All @@ -275,7 +270,6 @@ def test_cache_with_multiple_requests(
def test_delete_objects_injects_correct_checksum(
self, default_s3_client, mock_datetime
):
mock_datetime.utcnow.return_value = DATE
mock_datetime.now.return_value = DATE

with ClientHTTPStubber(default_s3_client) as stubber:
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/test_sts.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def setUp(self):
def test_presigned_url_contains_no_content_type(self):
timestamp = datetime(2017, 3, 22, 0, 0)
with mock.patch('botocore.auth.datetime.datetime') as _datetime:
_datetime.utcnow.return_value = timestamp
_datetime.now.return_value = timestamp
url = self.client.generate_presigned_url('get_caller_identity', {})

# There should be no 'content-type' in x-amz-signedheaders
Expand Down
16 changes: 6 additions & 10 deletions tests/unit/auth/test_signers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def setUp(self):
self.fixed_date = datetime.datetime(2014, 3, 10, 17, 2, 55, 0)
self.datetime_patch = mock.patch('botocore.auth.datetime.datetime')
self.datetime_mock = self.datetime_patch.start()
self.datetime_mock.utcnow.return_value = self.fixed_date
self.datetime_mock.now.return_value = self.fixed_date
self.datetime_mock.strptime.return_value = self.fixed_date

def tearDown(self):
Expand Down Expand Up @@ -521,17 +521,17 @@ def test_thread_safe_timestamp(self):
'datetime',
mock.Mock(wraps=datetime.datetime),
) as mock_datetime:
original_utcnow = datetime.datetime(2014, 1, 1, 0, 0)
original_now = datetime.datetime(2014, 1, 1, 0, 0)

mock_datetime.utcnow.return_value = original_utcnow
mock_datetime.now.return_value = original_now
# Go through the add_auth process once. This will attach
# a timestamp to the request at the beginning of auth.
auth.add_auth(request)
self.assertEqual(request.context['timestamp'], '20140101T000000Z')
# Ensure the date is in the Authorization header
self.assertIn('20140101', request.headers['Authorization'])
# Now suppose the utc time becomes the next day all of a sudden
mock_datetime.utcnow.return_value = datetime.datetime(
mock_datetime.now.return_value = datetime.datetime(
2014, 1, 2, 0, 0
)
# Smaller methods like the canonical request and string_to_sign
Expand Down Expand Up @@ -796,9 +796,7 @@ def setUp(self):
mock.Mock(wraps=datetime.datetime),
)
mocked_datetime = self.datetime_patcher.start()
mocked_datetime.utcnow.return_value = datetime.datetime(
2014, 1, 1, 0, 0
)
mocked_datetime.now.return_value = datetime.datetime(2014, 1, 1, 0, 0)

def tearDown(self):
self.datetime_patcher.stop()
Expand Down Expand Up @@ -1100,9 +1098,7 @@ def setUp(self):
mock.Mock(wraps=datetime.datetime),
)
mocked_datetime = self.datetime_patcher.start()
mocked_datetime.utcnow.return_value = datetime.datetime(
2014, 1, 1, 0, 0
)
mocked_datetime.now.return_value = datetime.datetime(2014, 1, 1, 0, 0)

def tearDown(self):
self.datetime_patcher.stop()
Expand Down
24 changes: 17 additions & 7 deletions tests/unit/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import subprocess
import tempfile
import time
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from pathlib import Path

import pytest
Expand Down Expand Up @@ -128,7 +128,7 @@ def setUp(self):

def test_refresh_needed(self):
# The expiry time was set for 30 minutes ago, so if we
# say the current time is utcnow(), then we should need
# say the current time is now(), then we should need
# a refresh.
self.mock_time.return_value = datetime.now(tzlocal())
self.assertTrue(self.creds.refresh_needed())
Expand Down Expand Up @@ -315,7 +315,9 @@ def test_expiration_in_datetime_format(self):
self.assertEqual(response, expected_response)

def test_retrieves_from_cache(self):
date_in_future = datetime.utcnow() + timedelta(seconds=1000)
date_in_future = datetime.now(timezone.utc).replace(
tzinfo=None
) + timedelta(seconds=1000)
utc_timestamp = date_in_future.isoformat() + 'Z'
cache_key = '793d6e2f27667ab2da104824407e486bfec24a47'
cache = {
Expand Down Expand Up @@ -749,7 +751,9 @@ def test_no_cache(self):
self.assertEqual(response, expected_response)

def test_retrieves_from_cache(self):
date_in_future = datetime.utcnow() + timedelta(seconds=1000)
date_in_future = datetime.now(timezone.utc).replace(
tzinfo=None
) + timedelta(seconds=1000)
utc_timestamp = date_in_future.isoformat() + 'Z'
cache_key = '793d6e2f27667ab2da104824407e486bfec24a47'
cache = {
Expand Down Expand Up @@ -867,7 +871,9 @@ def test_assume_role_with_no_cache(self):
mock_loader_cls.assert_called_with('/some/path/token.jwt')

def test_assume_role_retrieves_from_cache(self):
date_in_future = datetime.utcnow() + timedelta(seconds=1000)
date_in_future = datetime.now(timezone.utc).replace(
tzinfo=None
) + timedelta(seconds=1000)
utc_timestamp = date_in_future.isoformat() + 'Z'

cache_key = 'c29461feeacfbed43017d20612606ff76abc073d'
Expand Down Expand Up @@ -2037,7 +2043,9 @@ def test_assume_role_refresher_serializes_datetime(self):
self.assertEqual(expiry_time, '2016-11-06T01:30:00UTC')

def test_assume_role_retrieves_from_cache(self):
date_in_future = datetime.utcnow() + timedelta(seconds=1000)
date_in_future = datetime.now(timezone.utc).replace(
tzinfo=None
) + timedelta(seconds=1000)
utc_timestamp = date_in_future.isoformat() + 'Z'
self.fake_config['profiles']['development']['role_arn'] = 'myrole'

Expand Down Expand Up @@ -2066,7 +2074,9 @@ def test_assume_role_retrieves_from_cache(self):
self.assertEqual(creds.token, 'baz-cached')

def test_chain_prefers_cache(self):
date_in_future = datetime.utcnow() + timedelta(seconds=1000)
date_in_future = datetime.now(timezone.utc).replace(
tzinfo=None
) + timedelta(seconds=1000)
utc_timestamp = date_in_future.isoformat() + 'Z'

# The profile we will be using has a cache entry, but the profile it
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_signers.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ def setUp(self):
self.datetime_mock = self.datetime_patch.start()
self.fixed_date = datetime.datetime(2014, 3, 10, 17, 2, 55, 0)
self.fixed_delta = datetime.timedelta(seconds=3600)
self.datetime_mock.datetime.utcnow.return_value = self.fixed_date
self.datetime_mock.datetime.now.return_value = self.fixed_date
self.datetime_mock.timedelta.return_value = self.fixed_delta

def tearDown(self):
Expand Down Expand Up @@ -1146,7 +1146,7 @@ def test_generate_db_auth_token(self):
clock = datetime.datetime(2016, 11, 7, 17, 39, 33, tzinfo=tzutc())

with mock.patch('datetime.datetime') as dt:
dt.utcnow.return_value = clock
dt.now.return_value = clock
result = generate_db_auth_token(
self.client, hostname, port, username
)
Expand Down
4 changes: 3 additions & 1 deletion tests/unit/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3045,7 +3045,9 @@ def test_v1_disabled_by_config(self):

def _get_datetime(self, dt=None, offset=None, offset_func=operator.add):
if dt is None:
dt = datetime.datetime.utcnow()
dt = datetime.datetime.now(datetime.timezone.utc).replace(
tzinfo=None
)
if offset is not None:
dt = offset_func(dt, offset)

Expand Down