From 752465c3da2f19deca736a9508cc69756238beb3 Mon Sep 17 00:00:00 2001 From: jonathan343 Date: Thu, 15 Aug 2024 14:44:47 -0700 Subject: [PATCH] Partially address PR feedback. --- botocore/parsers.py | 25 +++++++++++-------------- botocore/serialize.py | 5 ++++- tests/unit/test_protocols.py | 11 ++++------- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/botocore/parsers.py b/botocore/parsers.py index c214262234..f74140cf09 100644 --- a/botocore/parsers.py +++ b/botocore/parsers.py @@ -124,6 +124,7 @@ from botocore.compat import ETree, XMLParseError from botocore.eventstream import EventStream, NoInitialResponseError from botocore.utils import ( + ensure_boolean, is_json_value_header, lowercase_dict, merge_dicts, @@ -204,7 +205,7 @@ class ResponseParser: # This is a list of known values for the "location" key in the # serialization dict. The location key tells us where in the response # to parse the value. - KNOWN_LOCATIONS = ['statusCode', 'header', 'headers'] + KNOWN_LOCATIONS = ('statusCode', 'header', 'headers') def __init__(self, timestamp_parser=None, blob_parser=None): if timestamp_parser is None: @@ -437,11 +438,10 @@ def _handle_structure(self, shape, node): member_shape = members[member_name] location = member_shape.serialization.get('location') if ( - location - and location in self.KNOWN_LOCATIONS + location in self.KNOWN_LOCATIONS or member_shape.serialization.get('eventheader') ): - # All members with know locations have already been handled, + # All members with known locations have already been handled, # so we don't need to parse these members. continue xml_name = self._member_key_name(member_shape, member_name) @@ -551,6 +551,8 @@ def _handle_blob(self, shape, text): class QueryParser(BaseXMLResponseParser): + ROOT_NODE_SUFFIX = 'Result' + def _do_error_parse(self, response, shape): xml_contents = response['body'] root = self._parse_xml_string_to_dom(xml_contents) @@ -589,9 +591,8 @@ def _parse_body_as_xml(self, response, shape, inject_metadata=True): operation_name = response.get("context", {}).get( "operation_name", "" ) - inferred_wrapper_name = operation_name + "Result" inferred_wrapper = self._find_result_wrapped_shape( - inferred_wrapper_name, root + f"{operation_name}{self.ROOT_NODE_SUFFIX}", root ) if inferred_wrapper is not None: start = inferred_wrapper @@ -615,6 +616,8 @@ def _inject_response_metadata(self, node, inject_into): class EC2QueryParser(QueryParser): + ROOT_NODE_SUFFIX = 'Response' + def _inject_response_metadata(self, node, inject_into): mapping = self._build_name_to_xml_node(node) child_node = mapping.get('requestId') @@ -979,7 +982,7 @@ def _parse_non_payload_attrs( for name in member_shapes: member_shape = member_shapes[name] location = member_shape.serialization.get('location') - if location is None or location not in self.KNOWN_LOCATIONS: + if location is None: continue elif location == 'statusCode': final_parsed[name] = self._parse_shape( @@ -1052,13 +1055,7 @@ def _initial_body_parse(self, body_contents): return self._parse_body_as_json(body_contents) def _handle_boolean(self, shape, value): - # It's possible to receive a boolean as a string - if isinstance(value, str): - if value == 'true': - return True - else: - return False - return value + return ensure_boolean(value) def _handle_integer(self, shape, value): return int(value) diff --git a/botocore/serialize.py b/botocore/serialize.py index a7474957f5..bdc9525b34 100644 --- a/botocore/serialize.py +++ b/botocore/serialize.py @@ -559,7 +559,10 @@ def _serialize_payload( body_params, shape_members[payload_member] ) else: - serialized['body'] = self._serialize_empty_body() + if shape_members[payload_member].is_tagged_union: + serialized['body'] = b'' + else: + serialized['body'] = self._serialize_empty_body() elif partitioned['body_kwargs']: serialized['body'] = self._serialize_body_params( partitioned['body_kwargs'], shape diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index dd8f338dda..501c27b509 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -52,7 +52,6 @@ """ import copy -import math import os import xml.etree.ElementTree as ET from base64 import b64decode @@ -99,12 +98,12 @@ 'rest-json': RestJSONParser, 'rest-xml': RestXMLParser, } -PROTOCOL_TEST_BLACKLIST = [ +PROTOCOL_TEST_BLOCKLIST = ( # These cases test functionality outside the serializers and parsers. "Test cases for QueryIdempotencyTokenAutoFill operation", "Test cases for PutWithContentEncoding operation", "Test cases for HttpChecksumRequired operation", -] +) class TestType(Enum): @@ -122,7 +121,7 @@ def _compliance_tests(test_type=None): for full_path in _walk_files(): if full_path.endswith('.json'): for model, case, basename in _load_cases(full_path): - if model.get('description') in PROTOCOL_TEST_BLACKLIST: + if model.get('description') in PROTOCOL_TEST_BLOCKLIST: continue if 'params' in case and inp: yield model, case, basename @@ -324,9 +323,7 @@ def _convert_bytes_to_str(parsed): def _special_floats_to_str(value): if isinstance(value, float): - if value in [float('Infinity'), float('-Infinity')] or math.isnan( - value - ): + if value in [float('Infinity'), float('-Infinity')] or value != value: return json.dumps(value) return value