diff --git a/.gitignore b/.gitignore index 1dbd294..26bc4c4 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ /aws-cli-2.11.26.tar.gz /aws-cli-2.11.27.tar.gz /aws-cli-2.12.0.tar.gz +/aws-cli-2.13.3.tar.gz diff --git a/assertions.patch b/assertions.patch new file mode 100644 index 0000000..3545005 --- /dev/null +++ b/assertions.patch @@ -0,0 +1,40 @@ +diff --git a/tests/functional/eks/test_kubeconfig.py b/tests/functional/eks/test_kubeconfig.py +index 3d1bcf8..687eef2 100644 +--- a/tests/functional/eks/test_kubeconfig.py ++++ b/tests/functional/eks/test_kubeconfig.py +@@ -121,8 +121,9 @@ class TestKubeconfigLoader(unittest.TestCase): + ]) + loaded_config = self._loader.load_kubeconfig(simple_path) + self.assertEqual(loaded_config.content, content) +- self._validator.validate_config.called_with(Kubeconfig(simple_path, +- content)) ++ validated_config = self._validator.validate_config.call_args.args[0] ++ self.assertEqual(validated_config.path, simple_path) ++ self.assertEqual(validated_config.content, content) + + def test_load_noexist(self): + no_exist_path = os.path.join(self._temp_directory, +@@ -130,17 +131,18 @@ class TestKubeconfigLoader(unittest.TestCase): + loaded_config = self._loader.load_kubeconfig(no_exist_path) + self.assertEqual(loaded_config.content, + _get_new_kubeconfig_content()) +- self._validator.validate_config.called_with( +- Kubeconfig(no_exist_path, _get_new_kubeconfig_content())) ++ validated_config = self._validator.validate_config.call_args.args[0] ++ self.assertEqual(validated_config.path, no_exist_path) ++ self.assertEqual(validated_config.content, _get_new_kubeconfig_content()) + + def test_load_empty(self): + empty_path = self._clone_config("valid_empty_existing") + loaded_config = self._loader.load_kubeconfig(empty_path) + self.assertEqual(loaded_config.content, + _get_new_kubeconfig_content()) +- self._validator.validate_config.called_with( +- Kubeconfig(empty_path, +- _get_new_kubeconfig_content())) ++ validated_config = self._validator.validate_config.call_args.args[0] ++ self.assertEqual(validated_config.path, empty_path) ++ self.assertEqual(validated_config.content, _get_new_kubeconfig_content()) + + def test_load_directory(self): + current_directory = self._temp_directory diff --git a/awscli2.spec b/awscli2.spec index 7065f3a..82010d3 100644 --- a/awscli2.spec +++ b/awscli2.spec @@ -1,7 +1,7 @@ %global pkgname aws-cli Name: awscli2 -Version: 2.12.0 +Version: 2.13.3 Release: %autorelease Summary: Universal Command Line Environment for AWS, version 2 @@ -13,9 +13,12 @@ URL: https://github.com/aws/aws-cli/tree/v2 Source0: https://github.com/aws/aws-cli/archive/%{version}/%{pkgname}-%{version}.tar.gz -# ruamel-yaml 0.17.22 changed whitespace formatting, breaking some TestUpdateKubeconfig tests -# add a workaround for that until upstream comes with a proper fix -Patch0: ruamel-yaml-0.17.22.patch +# adapt to whitespace formatting changes and removal of OrderedDict in ruamel-yaml +Patch0: ruamel-yaml-0.17.32.patch +# fix Python 3.12 incompatibilities +Patch1: python312.patch +# fix incorrect assertions in TestKubeconfigLoader +Patch2: assertions.patch BuildArch: noarch diff --git a/python312.patch b/python312.patch new file mode 100644 index 0000000..a3485d7 --- /dev/null +++ b/python312.patch @@ -0,0 +1,995 @@ +diff --git a/awscli/bcdoc/docstringparser.py b/awscli/bcdoc/docstringparser.py +index 868bd5d..3eaf662 100644 +--- a/awscli/bcdoc/docstringparser.py ++++ b/awscli/bcdoc/docstringparser.py +@@ -11,9 +11,10 @@ + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. + from botocore.compat import six ++from html import parser as html_parser + + +-class DocStringParser(six.moves.html_parser.HTMLParser): ++class DocStringParser(html_parser.HTMLParser): + """ + A simple HTML parser. Focused on converting the subset of HTML + that appears in the documentation strings of the JSON models into +@@ -23,20 +24,20 @@ class DocStringParser(six.moves.html_parser.HTMLParser): + def __init__(self, doc): + self.tree = None + self.doc = doc +- six.moves.html_parser.HTMLParser.__init__(self) ++ html_parser.HTMLParser.__init__(self) + + def reset(self): +- six.moves.html_parser.HTMLParser.reset(self) ++ html_parser.HTMLParser.reset(self) + self.tree = HTMLTree(self.doc) + + def feed(self, data): + # HTMLParser is an old style class, so the super() method will not work. +- six.moves.html_parser.HTMLParser.feed(self, data) ++ html_parser.HTMLParser.feed(self, data) + self.tree.write() + self.tree = HTMLTree(self.doc) + + def close(self): +- six.moves.html_parser.HTMLParser.close(self) ++ html_parser.HTMLParser.close(self) + # Write if there is anything remaining. + self.tree.write() + self.tree = HTMLTree(self.doc) +diff --git a/awscli/botocore/auth.py b/awscli/botocore/auth.py +index edae233..2483b32 100644 +--- a/awscli/botocore/auth.py ++++ b/awscli/botocore/auth.py +@@ -396,7 +396,7 @@ class SigV4Auth(BaseSigner): + def add_auth(self, request): + if self.credentials is None: + raise NoCredentialsError() +- datetime_now = datetime.datetime.utcnow() ++ datetime_now = datetime.datetime.now(datetime.UTC) + request.context['timestamp'] = datetime_now.strftime(SIGV4_TIMESTAMP) + # This could be a retry. Make sure the previous + # authorization header is removed first. +@@ -611,7 +611,7 @@ class S3SigV4PostAuth(SigV4Auth): + http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html + """ + def add_auth(self, request): +- datetime_now = datetime.datetime.utcnow() ++ datetime_now = datetime.datetime.now(datetime.UTC) + request.context['timestamp'] = datetime_now.strftime(SIGV4_TIMESTAMP) + + fields = {} +diff --git a/awscli/botocore/compat.py b/awscli/botocore/compat.py +index b189271..de182f4 100644 +--- a/awscli/botocore/compat.py ++++ b/awscli/botocore/compat.py +@@ -33,7 +33,7 @@ from urllib3 import exceptions + logger = logging.getLogger(__name__) + + +-from botocore.vendored.six.moves import http_client ++from http import client as http_client + + class HTTPHeaders(http_client.HTTPMessage): + pass +diff --git a/awscli/botocore/configloader.py b/awscli/botocore/configloader.py +index 3d1de2f..d8120c6 100644 +--- a/awscli/botocore/configloader.py ++++ b/awscli/botocore/configloader.py +@@ -18,6 +18,7 @@ import sys + + import botocore.exceptions + from botocore.compat import six ++import configparser + + + def multi_file_load_config(*filenames): +@@ -143,10 +144,10 @@ def raw_config_parse(config_filename, parse_subsections=True): + path = os.path.expanduser(path) + if not os.path.isfile(path): + raise botocore.exceptions.ConfigNotFound(path=_unicode_path(path)) +- cp = six.moves.configparser.RawConfigParser() ++ cp = configparser.RawConfigParser() + try: + cp.read([path]) +- except (six.moves.configparser.Error, UnicodeDecodeError): ++ except (configparser.Error, UnicodeDecodeError): + raise botocore.exceptions.ConfigParseError( + path=_unicode_path(path)) + else: +diff --git a/awscli/botocore/crt/auth.py b/awscli/botocore/crt/auth.py +index 534a7f8..474e675 100644 +--- a/awscli/botocore/crt/auth.py ++++ b/awscli/botocore/crt/auth.py +@@ -57,8 +57,7 @@ class CrtSigV4Auth(BaseSigner): + + # 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.UTC) + + # Use existing 'X-Amz-Content-SHA256' header if able + existing_sha256 = self._get_existing_sha256(request) +@@ -247,8 +246,7 @@ class CrtSigV4AsymAuth(BaseSigner): + + # 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.UTC) + + # Use existing 'X-Amz-Content-SHA256' header if able + existing_sha256 = self._get_existing_sha256(request) +diff --git a/awscli/botocore/docs/bcdoc/docstringparser.py b/awscli/botocore/docs/bcdoc/docstringparser.py +index 868bd5d..3eaf662 100644 +--- a/awscli/botocore/docs/bcdoc/docstringparser.py ++++ b/awscli/botocore/docs/bcdoc/docstringparser.py +@@ -11,9 +11,10 @@ + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. + from botocore.compat import six ++from html import parser as html_parser + + +-class DocStringParser(six.moves.html_parser.HTMLParser): ++class DocStringParser(html_parser.HTMLParser): + """ + A simple HTML parser. Focused on converting the subset of HTML + that appears in the documentation strings of the JSON models into +@@ -23,20 +24,20 @@ class DocStringParser(six.moves.html_parser.HTMLParser): + def __init__(self, doc): + self.tree = None + self.doc = doc +- six.moves.html_parser.HTMLParser.__init__(self) ++ html_parser.HTMLParser.__init__(self) + + def reset(self): +- six.moves.html_parser.HTMLParser.reset(self) ++ html_parser.HTMLParser.reset(self) + self.tree = HTMLTree(self.doc) + + def feed(self, data): + # HTMLParser is an old style class, so the super() method will not work. +- six.moves.html_parser.HTMLParser.feed(self, data) ++ html_parser.HTMLParser.feed(self, data) + self.tree.write() + self.tree = HTMLTree(self.doc) + + def close(self): +- six.moves.html_parser.HTMLParser.close(self) ++ html_parser.HTMLParser.close(self) + # Write if there is anything remaining. + self.tree.write() + self.tree = HTMLTree(self.doc) +diff --git a/awscli/botocore/httpsession.py b/awscli/botocore/httpsession.py +index 29b2103..d51dfdd 100644 +--- a/awscli/botocore/httpsession.py ++++ b/awscli/botocore/httpsession.py +@@ -59,7 +59,7 @@ from botocore.exceptions import ( + ReadTimeoutError, + SSLError, + ) +-from botocore.vendored.six.moves.urllib_parse import unquote ++from urllib.parse import unquote + + filter_ssl_warnings() + logger = logging.getLogger(__name__) +diff --git a/awscli/botocore/parsers.py b/awscli/botocore/parsers.py +index ffca974..367c867 100644 +--- a/awscli/botocore/parsers.py ++++ b/awscli/botocore/parsers.py +@@ -119,7 +119,8 @@ import json + import logging + import re + +-from botocore.compat import ETree, XMLParseError, six ++from botocore.compat import ETree, XMLParseError ++from http import client as http_client + from botocore.eventstream import EventStream, NoInitialResponseError + from botocore.utils import ( + is_json_value_header, +@@ -300,7 +301,7 @@ class ResponseParser(object): + "service, unable to populate error code and message.") + return { + 'Error': {'Code': str(response['status_code']), +- 'Message': six.moves.http_client.responses.get( ++ 'Message': http_client.responses.get( + response['status_code'], '')}, + 'ResponseMetadata': {}, + } +@@ -1035,7 +1036,7 @@ class RestXMLParser(BaseRestParser, BaseXMLResponseParser): + return { + 'Error': { + 'Code': str(response['status_code']), +- 'Message': six.moves.http_client.responses.get( ++ 'Message': http_client.responses.get( + response['status_code'], ''), + }, + 'ResponseMetadata': { +diff --git a/awscli/botocore/signers.py b/awscli/botocore/signers.py +index 77a9346..93b8af0 100644 +--- a/awscli/botocore/signers.py ++++ b/awscli/botocore/signers.py +@@ -532,7 +532,7 @@ class S3PostPresigner(object): + policy = {} + + # Create an expiration date for the policy +- datetime_now = datetime.datetime.utcnow() ++ datetime_now = datetime.datetime.now(datetime.UTC) + expire_date = datetime_now + datetime.timedelta(seconds=expires_in) + policy['expiration'] = expire_date.strftime(botocore.auth.ISO8601) + +diff --git a/awscli/botocore/utils.py b/awscli/botocore/utils.py +index 81b41dc..0740339 100644 +--- a/awscli/botocore/utils.py ++++ b/awscli/botocore/utils.py +@@ -70,7 +70,7 @@ from botocore.exceptions import ( + UnsupportedS3ControlArnError, + UnsupportedS3ControlConfigurationError, + ) +-from botocore.vendored.six.moves.urllib.request import getproxies, proxy_bypass ++from urllib.request import getproxies, proxy_bypass + from dateutil.tz import tzutc + from urllib3.exceptions import LocationParseError + +@@ -577,7 +577,7 @@ class InstanceMetadataFetcher(IMDSFetcher): + "ec2_credential_refresh_window", 60 * 10 + ) + refresh_interval_with_jitter = refresh_interval + random.randint(120, 600) +- current_time = datetime.datetime.utcnow() ++ current_time = datetime.datetime.now(datetime.UTC) + refresh_offset = datetime.timedelta(seconds=refresh_interval_with_jitter) + extension_time = expiration - refresh_offset + if current_time >= extension_time: +diff --git a/awscli/compat.py b/awscli/compat.py +index 705255d..b418c19 100644 +--- a/awscli/compat.py ++++ b/awscli/compat.py +@@ -25,6 +25,8 @@ from functools import partial + import urllib.parse as urlparse + from urllib.error import URLError + ++import queue ++import urllib.request + from botocore.compat import six + from botocore.compat import OrderedDict + +@@ -33,11 +35,10 @@ from botocore.compat import OrderedDict + # This may get large. + advance_iterator = six.advance_iterator + PY3 = six.PY3 +-queue = six.moves.queue +-shlex_quote = six.moves.shlex_quote ++shlex_quote = shlex.quote + StringIO = six.StringIO + BytesIO = six.BytesIO +-urlopen = six.moves.urllib.request.urlopen ++urlopen = urllib.request.urlopen + binary_type = six.binary_type + + # Most, but not all, python installations will have zlib. This is required to +diff --git a/awscli/customizations/cloudformation/deployer.py b/awscli/customizations/cloudformation/deployer.py +index 3733c55..48e69a6 100644 +--- a/awscli/customizations/cloudformation/deployer.py ++++ b/awscli/customizations/cloudformation/deployer.py +@@ -20,7 +20,7 @@ import collections + from awscli.customizations.cloudformation import exceptions + from awscli.customizations.cloudformation.artifact_exporter import mktempfile, parse_s3_url + +-from datetime import datetime ++from datetime import datetime, UTC + + LOG = logging.getLogger(__name__) + +@@ -85,7 +85,7 @@ class Deployer(object): + :return: + """ + +- now = datetime.utcnow().isoformat() ++ now = datetime.now(UTC).isoformat() + description = "Created by AWS CLI at {0} UTC".format(now) + + # Each changeset will get a unique name based on time +diff --git a/awscli/customizations/cloudtrail/validation.py b/awscli/customizations/cloudtrail/validation.py +index 78e2540..9a515e0 100644 +--- a/awscli/customizations/cloudtrail/validation.py ++++ b/awscli/customizations/cloudtrail/validation.py +@@ -19,7 +19,7 @@ import re + import sys + import zlib + from zlib import error as ZLibError +-from datetime import datetime, timedelta ++from datetime import datetime, timedelta, UTC + from dateutil import tz, parser + + import cryptography +@@ -401,7 +401,7 @@ class DigestTraverser(object): + :param end_date: Date to stop validating at (inclusive). + """ + if end_date is None: +- end_date = datetime.utcnow() ++ end_date = datetime.now(UTC) + end_date = normalize_date(end_date) + start_date = normalize_date(start_date) + bucket = self.starting_bucket +@@ -703,7 +703,7 @@ class CloudTrailValidateLogs(BasicCommand): + if args.end_time: + self.end_time = normalize_date(parse_date(args.end_time)) + else: +- self.end_time = normalize_date(datetime.utcnow()) ++ self.end_time = datetime.now(UTC) + if self.start_time > self.end_time: + raise ParamValidationError( + 'Invalid time range specified: start-time must ' +diff --git a/awscli/customizations/codecommit.py b/awscli/customizations/codecommit.py +index 6b30e83..935f27b 100644 +--- a/awscli/customizations/codecommit.py ++++ b/awscli/customizations/codecommit.py +@@ -150,7 +150,7 @@ class CodeCommitGetCommand(BasicCommand): + request = AWSRequest() + request.url = url_to_sign + request.method = 'GIT' +- now = datetime.datetime.utcnow() ++ now = datetime.datetime.now(datetime.UTC) + request.context['timestamp'] = now.strftime('%Y%m%dT%H%M%S') + split = urlsplit(request.url) + # we don't want to include the port number in the signature +diff --git a/awscli/customizations/codedeploy/push.py b/awscli/customizations/codedeploy/push.py +index 4c08664..8531c03 100644 +--- a/awscli/customizations/codedeploy/push.py ++++ b/awscli/customizations/codedeploy/push.py +@@ -16,7 +16,7 @@ import sys + import zipfile + import tempfile + import contextlib +-from datetime import datetime ++from datetime import datetime, UTC + + from botocore.exceptions import ClientError + +@@ -133,7 +133,7 @@ class Push(BasicCommand): + if not parsed_args.description: + parsed_args.description = ( + 'Uploaded by AWS CLI {0} UTC'.format( +- datetime.utcnow().isoformat() ++ datetime.now(UTC).isoformat() + ) + ) + +diff --git a/awscli/customizations/configure/__init__.py b/awscli/customizations/configure/__init__.py +index ab06305..55f11a9 100644 +--- a/awscli/customizations/configure/__init__.py ++++ b/awscli/customizations/configure/__init__.py +@@ -11,7 +11,7 @@ + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. + import string +-from botocore.vendored.six.moves import shlex_quote ++from shlex import quote as shlex_quote + + NOT_SET = '' + PREDEFINED_SECTION_NAMES = ('plugins') +diff --git a/awscli/customizations/datapipeline/__init__.py b/awscli/customizations/datapipeline/__init__.py +index c47ca94..309406c 100644 +--- a/awscli/customizations/datapipeline/__init__.py ++++ b/awscli/customizations/datapipeline/__init__.py +@@ -12,7 +12,7 @@ + # language governing permissions and limitations under the License. + + import json +-from datetime import datetime, timedelta ++from datetime import datetime, timedelta, UTC + + from awscli.formatter import get_formatter + from awscli.arguments import CustomArgument +@@ -186,7 +186,7 @@ class QueryArgBuilder(object): + """ + def __init__(self, current_time=None): + if current_time is None: +- current_time = datetime.utcnow() ++ current_time = datetime.now(UTC) + self.current_time = current_time + + def build_query(self, parsed_args): +diff --git a/awscli/customizations/ec2/bundleinstance.py b/awscli/customizations/ec2/bundleinstance.py +index 96d9ece..31a4962 100644 +--- a/awscli/customizations/ec2/bundleinstance.py ++++ b/awscli/customizations/ec2/bundleinstance.py +@@ -120,7 +120,7 @@ def _generate_policy(params): + # Called if there is no policy supplied by the user. + # Creates a policy that provides access for 24 hours. + delta = datetime.timedelta(hours=24) +- expires = datetime.datetime.utcnow() + delta ++ expires = datetime.datetime.now(datetime.UTC) + delta + expires_iso = expires.strftime("%Y-%m-%dT%H:%M:%S.%fZ") + policy = POLICY.format(expires=expires_iso, + bucket=params['Bucket'], +diff --git a/awscli/customizations/eks/get_token.py b/awscli/customizations/eks/get_token.py +index c85b86d..4d12661 100644 +--- a/awscli/customizations/eks/get_token.py ++++ b/awscli/customizations/eks/get_token.py +@@ -16,7 +16,7 @@ import json + import os + import sys + +-from datetime import datetime, timedelta ++from datetime import datetime, timedelta, UTC + from botocore.signers import RequestSigner + from botocore.model import ServiceId + +@@ -106,7 +106,7 @@ class GetTokenCommand(BasicCommand): + ] + + def get_expiration_time(self): +- token_expiration = datetime.utcnow() + timedelta( ++ token_expiration = datetime.now(UTC) + timedelta( + minutes=TOKEN_EXPIRATION_MINS + ) + return token_expiration.strftime('%Y-%m-%dT%H:%M:%SZ') +diff --git a/awscli/customizations/logs/tail.py b/awscli/customizations/logs/tail.py +index cb31510..b2f8563 100644 +--- a/awscli/customizations/logs/tail.py ++++ b/awscli/customizations/logs/tail.py +@@ -11,7 +11,8 @@ + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. + from collections import defaultdict +-from datetime import datetime, timedelta ++from datetime import datetime, timedelta, UTC ++import functools + import json + import re + import time +@@ -261,7 +262,7 @@ class TimestampUtils(object): + def __init__(self, now=None): + self._now = now + if now is None: +- self._now = datetime.utcnow ++ self._now = functools.partial(datetime.now, UTC) + + def to_epoch_millis(self, timestamp): + re_match = self._RELATIVE_TIMESTAMP_REGEX.match(timestamp) +diff --git a/awscli/customizations/opsworks.py b/awscli/customizations/opsworks.py +index a2a0c1e..217bfca 100644 +--- a/awscli/customizations/opsworks.py ++++ b/awscli/customizations/opsworks.py +@@ -507,7 +507,7 @@ class OpsWorksRegister(BasicCommand): + "Resource": arn, + } + if timeout is not None: +- valid_until = datetime.datetime.utcnow() + timeout ++ valid_until = datetime.datetime.now(datetime.UTC) + timeout + statement["Condition"] = { + "DateLessThan": { + "aws:CurrentTime": +diff --git a/tests/functional/botocore/test_credentials.py b/tests/functional/botocore/test_credentials.py +index 843be90..1bd9201 100644 +--- a/tests/functional/botocore/test_credentials.py ++++ b/tests/functional/botocore/test_credentials.py +@@ -19,7 +19,7 @@ import time + import mock + import tempfile + import shutil +-from datetime import datetime, timedelta ++from datetime import datetime, timedelta, UTC + import sys + + import pytest +@@ -47,8 +47,8 @@ from botocore.stub import Stubber + from botocore.tokens import SSOTokenProvider + from botocore.utils import datetime2timestamp + +-TIME_IN_ONE_HOUR = datetime.utcnow() + timedelta(hours=1) +-TIME_IN_SIX_MONTHS = datetime.utcnow() + timedelta(hours=4320) ++TIME_IN_ONE_HOUR = datetime.now(UTC) + timedelta(hours=1) ++TIME_IN_SIX_MONTHS = datetime.now(UTC) + timedelta(hours=4320) + + + class TestCredentialRefreshRaces(unittest.TestCase): +diff --git a/tests/functional/botocore/test_ec2.py b/tests/functional/botocore/test_ec2.py +index 795094e..fed43d2 100644 +--- a/tests/functional/botocore/test_ec2.py ++++ b/tests/functional/botocore/test_ec2.py +@@ -86,13 +86,13 @@ class TestCopySnapshotCustomization(BaseSessionTest): + '%s\n' + '\n' + ) +- self.now = datetime.datetime(2011, 9, 9, 23, 36) ++ self.now = datetime.datetime(2011, 9, 9, 23, 36, tzinfo=datetime.UTC) + self.datetime_patch = mock.patch.object( + botocore.auth.datetime, 'datetime', + 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(TestCopySnapshotCustomization, self).tearDown() +diff --git a/tests/functional/botocore/test_lex.py b/tests/functional/botocore/test_lex.py +index 7e7f619..eb623ec 100644 +--- a/tests/functional/botocore/test_lex.py ++++ b/tests/functional/botocore/test_lex.py +@@ -11,7 +11,7 @@ + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. + import mock +-from datetime import datetime ++from datetime import datetime, UTC + + from tests import BaseSessionTest, ClientHTTPStubber + +@@ -32,10 +32,10 @@ class TestLex(BaseSessionTest): + 'inputStream': b'' + } + +- timestamp = datetime(2017, 3, 22, 0, 0) ++ timestamp = datetime(2017, 3, 22, 0, 0, tzinfo=UTC) + + with mock.patch('botocore.auth.datetime') as _datetime: +- _datetime.datetime.utcnow.return_value = timestamp ++ _datetime.datetime.now.return_value = timestamp + self.http_stubber.add_response(body=b'{}') + with self.http_stubber: + self.client.post_content(**params) +diff --git a/tests/functional/botocore/test_sts.py b/tests/functional/botocore/test_sts.py +index cdc212a..75b367c 100644 +--- a/tests/functional/botocore/test_sts.py ++++ b/tests/functional/botocore/test_sts.py +@@ -10,7 +10,7 @@ + # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. +-from datetime import datetime ++from datetime import datetime, UTC + import re + + import mock +@@ -38,9 +38,9 @@ class TestSTSPresignedUrl(BaseSessionTest): + self.stubber.activate() + + def test_presigned_url_contains_no_content_type(self): +- timestamp = datetime(2017, 3, 22, 0, 0) ++ timestamp = datetime(2017, 3, 22, 0, 0, tzinfo=UTC) + with mock.patch('botocore.auth.datetime') as _datetime: +- _datetime.datetime.utcnow.return_value = timestamp ++ _datetime.datetime.now.return_value = timestamp + url = self.client.generate_presigned_url('get_caller_identity', {}) + + # There should be no 'content-type' in x-amz-signedheaders +diff --git a/tests/functional/ec2/test_bundle_instance.py b/tests/functional/ec2/test_bundle_instance.py +index 5bc3204..7dcc416 100644 +--- a/tests/functional/ec2/test_bundle_instance.py ++++ b/tests/functional/ec2/test_bundle_instance.py +@@ -34,7 +34,7 @@ class TestBundleInstance(BaseAWSCommandParamsTest): + + def setUp(self): + super(TestBundleInstance, self).setUp() +- # This mocks out datetime.datetime.utcnow() so that it always ++ # This mocks out datetime.datetime.now() so that it always + # returns the same datetime object. This is because this value + # is embedded into the policy file that is generated and we + # don't what the policy or its signature to change each time +@@ -44,7 +44,7 @@ class TestBundleInstance(BaseAWSCommandParamsTest): + mock.Mock(wraps=datetime.datetime) + ) + mocked_datetime = self.datetime_patcher.start() +- mocked_datetime.utcnow.return_value = datetime.datetime(2013, 8, 9) ++ mocked_datetime.now.return_value = datetime.datetime(2013, 8, 9, tzinfo=datetime.UTC) + + def tearDown(self): + super(TestBundleInstance, self).tearDown() +diff --git a/tests/functional/ec2instanceconnect/test_opentunnel.py b/tests/functional/ec2instanceconnect/test_opentunnel.py +index 83f824d..ddefc47 100644 +--- a/tests/functional/ec2instanceconnect/test_opentunnel.py ++++ b/tests/functional/ec2instanceconnect/test_opentunnel.py +@@ -310,10 +310,10 @@ def request_params_for_describe_eice(): + + + @pytest.fixture +-def datetime_utcnow_patch(): ++def datetime_now_patch(): + clock = datetime.datetime(2020, 1, 1, 1, 1, 1, tzinfo=tzutc()) + with mock.patch('datetime.datetime') as dt: +- dt.utcnow.return_value = clock ++ dt.now.return_value = clock + yield dt + + +@@ -393,7 +393,7 @@ class TestOpenTunnel: + describe_eice_response, + request_params_for_describe_instance, + request_params_for_describe_eice, +- datetime_utcnow_patch, ++ datetime_now_patch, + ): + cli_runner.env["AWS_USE_FIPS_ENDPOINT"] = "false" + cmdline = [ +diff --git a/tests/functional/eks/test_get_token.py b/tests/functional/eks/test_get_token.py +index 89801f9..ea48865 100644 +--- a/tests/functional/eks/test_get_token.py ++++ b/tests/functional/eks/test_get_token.py +@@ -11,7 +11,7 @@ + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. + import base64 +-from datetime import datetime ++from datetime import datetime, UTC + import json + import os + +@@ -80,7 +80,7 @@ class TestGetTokenCommand(BaseAWSCommandParamsTest): + + @mock.patch('awscli.customizations.eks.get_token.datetime') + def test_get_token(self, mock_datetime): +- mock_datetime.utcnow.return_value = datetime(2019, 10, 23, 23, 0, 0, 0) ++ mock_datetime.now.return_value = datetime(2019, 10, 23, 23, 0, 0, 0, tzinfo=UTC) + cmd = 'eks get-token --cluster-name %s' % self.cluster_name + response = self.run_get_token(cmd) + self.assertEqual( +@@ -98,7 +98,7 @@ class TestGetTokenCommand(BaseAWSCommandParamsTest): + + @mock.patch('awscli.customizations.eks.get_token.datetime') + def test_query_nested_object(self, mock_datetime): +- mock_datetime.utcnow.return_value = datetime(2019, 10, 23, 23, 0, 0, 0) ++ mock_datetime.now.return_value = datetime(2019, 10, 23, 23, 0, 0, 0, tzinfo=UTC) + cmd = 'eks get-token --cluster-name %s' % self.cluster_name + cmd += ' --query status' + response = self.run_get_token(cmd) +@@ -120,7 +120,7 @@ class TestGetTokenCommand(BaseAWSCommandParamsTest): + + @mock.patch('awscli.customizations.eks.get_token.datetime') + def test_output_text(self, mock_datetime): +- mock_datetime.utcnow.return_value = datetime(2019, 10, 23, 23, 0, 0, 0) ++ mock_datetime.now.return_value = datetime(2019, 10, 23, 23, 0, 0, 0, tzinfo=UTC) + cmd = 'eks get-token --cluster-name %s' % self.cluster_name + cmd += ' --output text' + stdout, _, _ = self.run_cmd(cmd) +@@ -130,7 +130,7 @@ class TestGetTokenCommand(BaseAWSCommandParamsTest): + + @mock.patch('awscli.customizations.eks.get_token.datetime') + def test_output_table(self, mock_datetime): +- mock_datetime.utcnow.return_value = datetime(2019, 10, 23, 23, 0, 0, 0) ++ mock_datetime.now.return_value = datetime(2019, 10, 23, 23, 0, 0, 0, tzinfo=UTC) + cmd = 'eks get-token --cluster-name %s' % self.cluster_name + cmd += ' --output table' + stdout, _, _ = self.run_cmd(cmd) +diff --git a/tests/functional/logs/test_tail.py b/tests/functional/logs/test_tail.py +index 6049a7f..5707da9 100644 +--- a/tests/functional/logs/test_tail.py ++++ b/tests/functional/logs/test_tail.py +@@ -152,7 +152,7 @@ class TestTailCommand(BaseAWSCommandParamsTest): + + def test_tail_defaults_to_10m(self): + datetime_mock = mock.Mock(wraps=datetime) +- datetime_mock.utcnow = mock.Mock( ++ datetime_mock.now = mock.Mock( + return_value=datetime(1970, 1, 1, 0, 10, 1, tzinfo=tz.tzutc())) + with mock.patch('awscli.customizations.logs.tail.datetime', + new=datetime_mock): +@@ -177,7 +177,7 @@ class TestTailCommand(BaseAWSCommandParamsTest): + + def test_tail_with_relative_since(self): + datetime_mock = mock.Mock(wraps=datetime) +- datetime_mock.utcnow = mock.Mock( ++ datetime_mock.now = mock.Mock( + return_value=datetime(1970, 1, 1, 0, 0, 2, tzinfo=tz.tzutc())) + with mock.patch('awscli.customizations.logs.tail.datetime', + new=datetime_mock): +diff --git a/tests/functional/rds/test_generate_db_auth_token.py b/tests/functional/rds/test_generate_db_auth_token.py +index 795b939..4562b92 100644 +--- a/tests/functional/rds/test_generate_db_auth_token.py ++++ b/tests/functional/rds/test_generate_db_auth_token.py +@@ -53,7 +53,7 @@ class TestGenerateDBAuthToken(BaseAWSCommandParamsTest): + 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 + stdout, _, _ = self.run_cmd(command, expected_rc=0) + + expected = ( +diff --git a/tests/functional/s3/test_presign_command.py b/tests/functional/s3/test_presign_command.py +index 2db338a..8b3120a 100644 +--- a/tests/functional/s3/test_presign_command.py ++++ b/tests/functional/s3/test_presign_command.py +@@ -18,13 +18,13 @@ from awscli.testutils import BaseAWSCommandParamsTest, mock, temporary_file + from awscli.testutils import create_clidriver + + +-# Values used to fix time.time() and datetime.datetime.utcnow() ++# Values used to fix time.time() and datetime.datetime.now() + # so we know the exact values of the signatures generated. + FROZEN_TIMESTAMP = 1471305652 + DEFAULT_EXPIRES = 3600 + FROZEN_TIME = mock.Mock(return_value=FROZEN_TIMESTAMP) + FROZEN_DATETIME = mock.Mock( +- return_value=datetime.datetime(2016, 8, 18, 14, 33, 3, 0)) ++ return_value=datetime.datetime(2016, 8, 18, 14, 33, 3, 0, tzinfo=datetime.UTC)) + + + class TestPresignCommand(BaseAWSCommandParamsTest): +@@ -78,7 +78,7 @@ class TestPresignCommand(BaseAWSCommandParamsTest): + def get_presigned_url_for_cmd(self, cmdline): + with mock.patch('time.time', FROZEN_TIME): + with mock.patch('datetime.datetime') as d: +- d.utcnow = FROZEN_DATETIME ++ d.now = FROZEN_DATETIME + stdout = self.assert_params_for_cmd(cmdline, None)[0].strip() + return stdout + +diff --git a/tests/integration/botocore/test_client_http.py b/tests/integration/botocore/test_client_http.py +index d6b0902..4e66fdf 100644 +--- a/tests/integration/botocore/test_client_http.py ++++ b/tests/integration/botocore/test_client_http.py +@@ -8,7 +8,8 @@ from contextlib import contextmanager + + import botocore.session + from botocore.config import Config +-from botocore.vendored.six.moves import BaseHTTPServer, socketserver ++from http import server as BaseHTTPServer ++import socketserver + from botocore.exceptions import ( + ConnectTimeoutError, ReadTimeoutError, EndpointConnectionError, + ConnectionClosedError, ClientError, ProxyConnectionError +diff --git a/tests/unit/botocore/auth/test_signers.py b/tests/unit/botocore/auth/test_signers.py +index 73d3b12..3b3922d 100644 +--- a/tests/unit/botocore/auth/test_signers.py ++++ b/tests/unit/botocore/auth/test_signers.py +@@ -31,7 +31,7 @@ class BaseTestWithFixedDate(unittest.TestCase): + 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.replace(tzinfo=datetime.UTC) + self.datetime_mock.strptime.return_value = self.fixed_date + + def tearDown(self): +@@ -358,9 +358,9 @@ class TestSigV4(unittest.TestCase): + with mock.patch.object( + botocore.auth.datetime, '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, tzinfo=datetime.UTC) + +- 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) +@@ -368,8 +368,8 @@ class TestSigV4(unittest.TestCase): + # 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( +- 2014, 1, 2, 0, 0) ++ mock_datetime.now.return_value = datetime.datetime( ++ 2014, 1, 2, 0, 0, tzinfo=datetime.UTC) + # Smaller methods like the canonical request and string_to_sign + # should have the timestamp attached to the request in their + # body and not what the time is now mocked as. This is to ensure +@@ -535,8 +535,8 @@ class TestSigV4Presign(BasePresignTest): + 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, tzinfo=datetime.UTC) + + def tearDown(self): + self.datetime_patcher.stop() +@@ -730,8 +730,8 @@ class TestS3SigV4Post(BaseS3PresignPostTest): + 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, tzinfo=datetime.UTC) + + def tearDown(self): + self.datetime_patcher.stop() +diff --git a/tests/unit/botocore/test_client.py b/tests/unit/botocore/test_client.py +index f28b959..1b3d56b 100644 +--- a/tests/unit/botocore/test_client.py ++++ b/tests/unit/botocore/test_client.py +@@ -960,7 +960,7 @@ class TestAutoGeneratedClient(unittest.TestCase): + lines = [ + (' Creates an iterator that will paginate through responses ' + 'from :py:meth:`MyService.Client.test_operation`.'), +- ' **Request Syntax** ', ++ ' **Request Syntax**', + ' ::', + ' response_iterator = paginator.paginate(', + " Foo='string',", +@@ -976,17 +976,17 @@ class TestAutoGeneratedClient(unittest.TestCase): + ' :type Bar: string', + ' :param Bar: Documents Bar', + ' :type PaginationConfig: dict', +- ' :param PaginationConfig: ', ++ ' :param PaginationConfig:', + (' A dictionary that provides parameters to control ' + 'pagination.'), +- ' - **MaxItems** *(integer) --* ', ++ ' - **MaxItems** *(integer) --*', + (' The total number of items to return. If the total ' + 'number of items available is more than the value specified ' + 'in max-items then a ``NextToken`` will be provided in the ' + 'output that you can use to resume pagination.'), +- ' - **PageSize** *(integer) --* ', ++ ' - **PageSize** *(integer) --*', + ' The size of each page.', +- ' - **StartingToken** *(string) --* ', ++ ' - **StartingToken** *(string) --*', + (' A token to specify where to start paginating. This is ' + 'the ``NextToken`` from a previous response.'), + ' :returns: None', +diff --git a/tests/unit/botocore/test_credentials.py b/tests/unit/botocore/test_credentials.py +index cc49596..0a5e4d7 100644 +--- a/tests/unit/botocore/test_credentials.py ++++ b/tests/unit/botocore/test_credentials.py +@@ -11,7 +11,7 @@ + # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. +-from datetime import datetime, timedelta ++from datetime import datetime, timedelta, UTC + import subprocess + import mock + import os +@@ -291,8 +291,8 @@ class TestAssumeRoleCredentialFetcher(BaseEnvVar): + self.assertEqual(response, expected_response) + + def test_retrieves_from_cache(self): +- date_in_future = datetime.utcnow() + timedelta(seconds=1000) +- utc_timestamp = date_in_future.isoformat() + 'Z' ++ date_in_future = datetime.now(UTC) + timedelta(seconds=1000) ++ utc_timestamp = date_in_future.isoformat() + cache_key = ( + '793d6e2f27667ab2da104824407e486bfec24a47' + ) +@@ -703,8 +703,8 @@ class TestAssumeRoleWithWebIdentityCredentialFetcher(BaseEnvVar): + self.assertEqual(response, expected_response) + + def test_retrieves_from_cache(self): +- date_in_future = datetime.utcnow() + timedelta(seconds=1000) +- utc_timestamp = date_in_future.isoformat() + 'Z' ++ date_in_future = datetime.now(UTC) + timedelta(seconds=1000) ++ utc_timestamp = date_in_future.isoformat() + cache_key = ( + '793d6e2f27667ab2da104824407e486bfec24a47' + ) +@@ -823,8 +823,8 @@ class TestAssumeRoleWithWebIdentityCredentialProvider(unittest.TestCase): + 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) +- utc_timestamp = date_in_future.isoformat() + 'Z' ++ date_in_future = datetime.now(UTC) + timedelta(seconds=1000) ++ utc_timestamp = date_in_future.isoformat() + + cache_key = ( + 'c29461feeacfbed43017d20612606ff76abc073d' +@@ -1961,8 +1961,8 @@ class TestAssumeRoleCredentialProvider(unittest.TestCase): + 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) +- utc_timestamp = date_in_future.isoformat() + 'Z' ++ date_in_future = datetime.now(UTC) + timedelta(seconds=1000) ++ utc_timestamp = date_in_future.isoformat() + self.fake_config['profiles']['development']['role_arn'] = 'myrole' + + cache_key = ( +@@ -1989,8 +1989,8 @@ class TestAssumeRoleCredentialProvider(unittest.TestCase): + self.assertEqual(creds.token, 'baz-cached') + + def test_chain_prefers_cache(self): +- date_in_future = datetime.utcnow() + timedelta(seconds=1000) +- utc_timestamp = date_in_future.isoformat() + 'Z' ++ date_in_future = datetime.now(UTC) + timedelta(seconds=1000) ++ utc_timestamp = date_in_future.isoformat() + + # The profile we will be using has a cache entry, but the profile it + # is sourcing from does not. This should result in the cached +diff --git a/tests/unit/botocore/test_signers.py b/tests/unit/botocore/test_signers.py +index e06e0c1..fc56d71 100644 +--- a/tests/unit/botocore/test_signers.py ++++ b/tests/unit/botocore/test_signers.py +@@ -609,9 +609,9 @@ class TestS3PostPresigner(BaseSignerTest): + + self.datetime_patch = mock.patch('botocore.signers.datetime') + self.datetime_mock = self.datetime_patch.start() +- self.fixed_date = datetime.datetime(2014, 3, 10, 17, 2, 55, 0) ++ self.fixed_date = datetime.datetime(2014, 3, 10, 17, 2, 55, 0, tzinfo=datetime.UTC) + 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): +@@ -979,7 +979,7 @@ class TestGenerateDBAuthToken(BaseSignerTest): + 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) + +diff --git a/tests/unit/botocore/test_utils.py b/tests/unit/botocore/test_utils.py +index a4d7f13..97df14b 100644 +--- a/tests/unit/botocore/test_utils.py ++++ b/tests/unit/botocore/test_utils.py +@@ -1004,7 +1004,7 @@ class TestSwitchToChunkedEncodingForNonSeekableObjects(unittest.TestCase): + def test_switch_to_chunked_encodeing_for_stream_like_object(self): + request = AWSRequest( + method='POST', headers={}, +- data=io.BufferedIOBase(b"some initial binary data"), ++ data=io.BufferedIOBase(), + url='https://foo.amazonaws.com/bucket/key.txt' + ) + prepared_request = request.prepare() +@@ -2794,7 +2794,7 @@ class TestInstanceMetadataFetcher(unittest.TestCase): + self, dt=None, offset=None, offset_func=operator.add + ): + if dt is None: +- dt = datetime.datetime.utcnow() ++ dt = datetime.datetime.now(datetime.UTC) + if offset is not None: + dt = offset_func(dt, offset) + +diff --git a/tests/unit/botocore/test_waiters.py b/tests/unit/botocore/test_waiters.py +index 27fbe1f..b79e173 100644 +--- a/tests/unit/botocore/test_waiters.py ++++ b/tests/unit/botocore/test_waiters.py +@@ -648,7 +648,7 @@ class TestCreateWaiter(unittest.TestCase): + (' Polls :py:meth:`MyService.Client.foo` every 1 ' + 'seconds until a successful state is reached. An error ' + 'is returned after 1 failed checks.'), +- ' **Request Syntax** ', ++ ' **Request Syntax**', + ' ::', + ' waiter.wait(', + " bar='string'", +diff --git a/tests/unit/customizations/test_opsworks.py b/tests/unit/customizations/test_opsworks.py +index 1471ba9..3e30717 100644 +--- a/tests/unit/customizations/test_opsworks.py ++++ b/tests/unit/customizations/test_opsworks.py +@@ -34,8 +34,8 @@ class TestOpsWorksBase(unittest.TestCase): + mock.Mock(wraps=datetime.datetime) + ) + mocked_datetime = self.datetime_patcher.start() +- mocked_datetime.utcnow.return_value = datetime.datetime( +- 2013, 8, 9, 23, 42) ++ mocked_datetime.now.return_value = datetime.datetime( ++ 2013, 8, 9, 23, 42, tzinfo=datetime.UTC) + + def tearDown(self): + self.datetime_patcher.stop() +diff --git a/tests/utils/botocore/__init__.py b/tests/utils/botocore/__init__.py +index 964ec88..2213f96 100644 +--- a/tests/utils/botocore/__init__.py ++++ b/tests/utils/botocore/__init__.py +@@ -555,7 +555,7 @@ class FreezeTime(contextlib.ContextDecorator): + + def __init__(self, module, date=None): + if date is None: +- date = datetime.datetime.utcnow() ++ date = datetime.datetime.now(datetime.UTC) + self.date = date + self.datetime_patcher = mock.patch.object( + module, 'datetime', +@@ -564,7 +564,7 @@ class FreezeTime(contextlib.ContextDecorator): + + 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() diff --git a/ruamel-yaml-0.17.22.patch b/ruamel-yaml-0.17.22.patch deleted file mode 100644 index 55045f1..0000000 --- a/ruamel-yaml-0.17.22.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/awscli/customizations/eks/ordered_yaml.py b/awscli/customizations/eks/ordered_yaml.py -index 23834e0..828280a 100644 ---- a/awscli/customizations/eks/ordered_yaml.py -+++ b/awscli/customizations/eks/ordered_yaml.py -@@ -46,6 +46,7 @@ def ordered_yaml_dump(to_dump, stream=None): - :type stream: file - """ - yaml = ruamel.yaml.YAML(typ="safe", pure=True) -+ yaml.width = 99999 - yaml.default_flow_style = False - yaml.Representer.add_representer(OrderedDict, _ordered_representer) - diff --git a/ruamel-yaml-0.17.32.patch b/ruamel-yaml-0.17.32.patch new file mode 100644 index 0000000..eee82b9 --- /dev/null +++ b/ruamel-yaml-0.17.32.patch @@ -0,0 +1,77 @@ +diff --git a/awscli/customizations/cloudformation/yamlhelper.py b/awscli/customizations/cloudformation/yamlhelper.py +index abdc749..ef32415 100644 +--- a/awscli/customizations/cloudformation/yamlhelper.py ++++ b/awscli/customizations/cloudformation/yamlhelper.py +@@ -92,6 +92,7 @@ def yaml_dump(dict_to_dump): + yaml.Representer = FlattenAliasRepresenter + _add_yaml_1_1_boolean_resolvers(yaml.Resolver) + yaml.Representer.add_representer(OrderedDict, _dict_representer) ++ yaml.Representer.add_representer(dict, _dict_representer) + + return dump_yaml_to_str(yaml, dict_to_dump) + +diff --git a/awscli/customizations/eks/kubeconfig.py b/awscli/customizations/eks/kubeconfig.py +index 5130f7f..64526a7 100644 +--- a/awscli/customizations/eks/kubeconfig.py ++++ b/awscli/customizations/eks/kubeconfig.py +@@ -44,7 +44,7 @@ def _get_new_kubeconfig_content(): + ("contexts", []), + ("current-context", ""), + ("kind", "Config"), +- ("preferences", OrderedDict()), ++ ("preferences", {}), + ("users", []) + ]) + +@@ -121,7 +121,7 @@ class KubeconfigValidator(object): + if (key in config.content and + type(config.content[key]) == list): + for element in config.content[key]: +- if not isinstance(element, OrderedDict): ++ if not isinstance(element, dict): + raise KubeconfigCorruptedError( + f"Entry in {key} not a {dict}. ") + +diff --git a/awscli/customizations/eks/ordered_yaml.py b/awscli/customizations/eks/ordered_yaml.py +index 23834e0..1ea6341 100644 +--- a/awscli/customizations/eks/ordered_yaml.py ++++ b/awscli/customizations/eks/ordered_yaml.py +@@ -46,8 +46,10 @@ def ordered_yaml_dump(to_dump, stream=None): + :type stream: file + """ + yaml = ruamel.yaml.YAML(typ="safe", pure=True) ++ yaml.width = 99999 + yaml.default_flow_style = False + yaml.Representer.add_representer(OrderedDict, _ordered_representer) ++ yaml.Representer.add_representer(dict, _ordered_representer) + + if stream is None: + return dump_yaml_to_str(yaml, to_dump) +diff --git a/tests/unit/customizations/cloudformation/test_yamlhelper.py b/tests/unit/customizations/cloudformation/test_yamlhelper.py +index 9f511b0..29a93a5 100644 +--- a/tests/unit/customizations/cloudformation/test_yamlhelper.py ++++ b/tests/unit/customizations/cloudformation/test_yamlhelper.py +@@ -139,10 +139,10 @@ class TestYaml(BaseYAMLTest): + ' Name: name1\n' + ) + output_dict = yaml_parse(input_template) +- expected_dict = OrderedDict([ +- ('B_Resource', OrderedDict([('Key2', {'Name': 'name2'}), ('Key1', {'Name': 'name1'})])), +- ('A_Resource', OrderedDict([('Key2', {'Name': 'name2'}), ('Key1', {'Name': 'name1'})])) +- ]) ++ expected_dict = { ++ 'B_Resource': {'Key2': {'Name': 'name2'}, 'Key1': {'Name': 'name1'}}, ++ 'A_Resource': {'Key2': {'Name': 'name2'}, 'Key1': {'Name': 'name1'}} ++ } + self.assertEqual(expected_dict, output_dict) + + output_template = yaml_dump(output_dict) +@@ -156,7 +156,7 @@ class TestYaml(BaseYAMLTest): + <<: *base + """ + output = yaml_parse(test_yaml) +- self.assertTrue(isinstance(output, OrderedDict)) ++ self.assertTrue(isinstance(output, dict)) + self.assertEqual(output.get('test').get('property'), 'value') + + def test_unroll_yaml_anchors(self): diff --git a/sources b/sources index 0cbf102..47cf0d5 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (aws-cli-2.12.0.tar.gz) = f11988e98363ebb3cff2e28b5bb7a5c406047d9d8dcfdc33efae20c942011bdd827dc30057d151957ad1d79e8e868620016529ee6845acc705228d3899589521 +SHA512 (aws-cli-2.13.3.tar.gz) = 6bb9f378b0e5eaa41e9843739af50039efadc6c08bd88305d8ad51c5d06acd19b74401f8184f205b76a3ac8f8b8cdfde0b0bddef05037446b4f56d607d6cd44b