a 97a@szdZddlZddlZddlZddlZddlmZmZmZddl m Z m Z ddl m Z mZmZmZeeZe ZGdddeZdd Zd d ZGd d d eZGdddeZGdddeZGdddeZGdddeZGdddeZGdddeZ Gddde eZ!Gddde eZ"GdddeZ#Gd d!d!eZ$Gd"d#d#e$eZ%Gd$d%d%e$eZ&eee#e%e&d&Z'dS)'aResponse parsers for the various protocol types. The module contains classes that can take an HTTP response, and given an output shape, parse the response into a dict according to the rules in the output shape. There are many similarities amongst the different protocols with regard to response parsing, and the code is structured in a way to avoid code duplication when possible. The diagram below is a diagram showing the inheritance hierarchy of the response classes. :: +--------------+ |ResponseParser| +--------------+ ^ ^ ^ +--------------------+ | +-------------------+ | | | +----------+----------+ +------+-------+ +-------+------+ |BaseXMLResponseParser| |BaseRestParser| |BaseJSONParser| +---------------------+ +--------------+ +--------------+ ^ ^ ^ ^ ^ ^ | | | | | | | | | | | | | ++----------+-+ +-+-----------++ | | |RestXMLParser| |RestJSONParser| | +-----+-----+ +-------------+ +--------------+ +----+-----+ |QueryParser| |JSONParser| +-----------+ +----------+ The diagram above shows that there is a base class, ``ResponseParser`` that contains logic that is similar amongst all the different protocols (``query``, ``json``, ``rest-json``, ``rest-xml``). Amongst the various services there is shared logic that can be grouped several ways: * The ``query`` and ``rest-xml`` both have XML bodies that are parsed in the same way. * The ``json`` and ``rest-json`` protocols both have JSON bodies that are parsed in the same way. * The ``rest-json`` and ``rest-xml`` protocols have additional attributes besides body parameters that are parsed the same (headers, query string, status code). This is reflected in the class diagram above. The ``BaseXMLResponseParser`` and the BaseJSONParser contain logic for parsing the XML/JSON body, and the BaseRestParser contains logic for parsing out attributes that come from other parts of the HTTP response. Classes like the ``RestXMLParser`` inherit from the ``BaseXMLResponseParser`` to get the XML body parsing logic and the ``BaseRestParser`` to get the HTTP header/status code/query string parsing. Additionally, there are event stream parsers that are used by the other parsers to wrap streaming bodies that represent a stream of events. The BaseEventStreamParser extends from ResponseParser and defines the logic for parsing values from the headers and payload of a message from the underlying binary encoding protocol. Currently, event streams support parsing bodies encoded as JSON and XML through the following hierarchy. +--------------+ |ResponseParser| +--------------+ ^ ^ ^ +--------------------+ | +------------------+ | | | +----------+----------+ +----------+----------+ +-------+------+ |BaseXMLResponseParser| |BaseEventStreamParser| |BaseJSONParser| +---------------------+ +---------------------+ +--------------+ ^ ^ ^ ^ | | | | | | | | +-+----------------+-+ +-+-----------------+-+ |EventStreamXMLParser| |EventStreamJSONParser| +--------------------+ +---------------------+ Return Values ============= Each call to ``parse()`` returns a dict has this form:: Standard Response { "ResponseMetadata": {"RequestId": } } Error response { "ResponseMetadata": {"RequestId": } "Error": { "Code": , "Message": , "Type": , } } N)sixETree XMLParseError) EventStreamNoInitialResponseError)parse_timestamp merge_dictsis_json_value_headerlowercase_dictc@s$eZdZddZddZddZdS)ResponseParserFactorycCs i|_dSN) _defaults)selfrk/private/var/folders/s6/9n5zrl012gv99k63s4q6ccsd4s6mqz/T/pip-target-f5cq3f2q/lib/python/botocore/parsers.py__init__szResponseParserFactory.__init__cKs|j|dS)aOSet default arguments when a parser instance is created. You can specify any kwargs that are allowed by a ResponseParser class. There are currently two arguments: * timestamp_parser - A callable that can parse a timestamp string * blob_parser - A callable that can parse a blob type N)r update)rkwargsrrrset_parser_defaultss z)ResponseParserFactory.set_parser_defaultscCst|}|fi|jSr )PROTOCOL_PARSERSr )rZ protocol_nameZ parser_clsrrr create_parsersz#ResponseParserFactory.create_parserN)__name__ __module__ __qualname__rrrrrrrr s r cCs t|Sr )r r)protocolrrrrsrcsfdd}|S)Ncs.t|dr|j}|dur"d}n|}|||S)Ntext)hasattrr)rshapenode_or_stringrfuncrr_get_text_contents  z(_text_content.._get_text_contentr)r!r"rr r _text_contents r#c@s eZdZdS)ResponseParserErrorN)rrrrrrrr$sr$c@seZdZdZdZdZdddZddZdd Zd d Z d d Z ddZ ddZ ddZ ddZddZddZddZddZdS)ResponseParseraoBase class for response parsing. This class represents the interface that all ResponseParsers for the various protocols must implement. This class will take an HTTP response and a model shape and parse the HTTP response into a dictionary. There is a single public method exposed: ``parse``. See the ``parse`` docstring for more info. zutf-8NcCsH|dur t}||_|dur |j}||_d|_|jdurD||||_dSr )DEFAULT_TIMESTAMP_PARSER_timestamp_parser_default_blob_parser _blob_parser_event_stream_parserEVENT_STREAM_PARSER_CLSrZtimestamp_parserZ blob_parserrrrrs zResponseParser.__init__cCs t|Sr )base64 b64decode)rvaluerrrr(sz#ResponseParser._default_blob_parsercCstd|dtd|d|ddkrj||rB||}qv||r\|||}|S|||}n |||}|r|j dr|St |t r| di}|d|d <|d}t ||d <||d<|S) a>Parse the HTTP response given a shape. :param response: The HTTP response dictionary. This is a dictionary that represents the HTTP request. The dictionary must have the following keys, ``body``, ``headers``, and ``status_code``. :param shape: The model shape describing the expected output. :return: Returns a dictionary representing the parsed response described by the model. In addition to the shape described from the model, each response will also have a ``ResponseMetadata`` which contains metadata about the response, which contains at least two keys containing ``RequestId`` and ``HTTPStatusCode``. Some responses may populate additional keys, but ``RequestId`` will always be present. zResponse headers: %sheaderszResponse body: %sbody status_codei- eventstreamResponseMetadataZHTTPStatusCodeZ HTTPHeaders) LOGdebug_is_generic_error_response_do_generic_error_parse_is_modeled_error_shape_do_modeled_error_parse_do_error_parse _do_parse serializationget isinstancedictr )rresponserparsedZresponse_metadatar0rrrparses&          zResponseParser.parsecCs|duo|jddS)N exceptionF)metadatar>)rrrrrr9sz&ResponseParser._is_modeled_error_shapecCsD|ddkr@d|vs |ddur$dS|d}|dp>| SdS)Nr2ir1Ts)strip startswith)rrAr1rrrr7 s  z)ResponseParser._is_generic_error_responsecCs4tdt|dtjjj|dddidS)NzlReceived a non protocol specific error response from the service, unable to populate error code and message.r2rCodeMessageErrorr4)r5r6strrmoves http_client responsesr>rrArrrr8s   z&ResponseParser._do_generic_error_parsecCstd|jjdS)Nz %s._do_parseNotImplementedError __class__rrrArrrrr<*szResponseParser._do_parsecCstd|jjdS)Nz%s._do_error_parserRrUrrrr;-s zResponseParser._do_error_parsecCstd|jjdS)Nz%s._do_modeled_error_parserR)rrArrBrrrr:1s z&ResponseParser._do_modeled_error_parsecCst|d|j|j}|||S)Nz _handle_%s)getattr type_name_default_handle)rrnodehandlerrrr _parse_shape5s zResponseParser._parse_shapecCs*g}|j}|D]}||||q|Sr )memberappendr[)rrrYrB member_shapeitemrrr _handle_list:s zResponseParser._handle_listcCs|Sr rrrr/rrrrXCszResponseParser._default_handlecCs&|j}|dd}t|d|||S)NcontextZoperation_namer1)r*r>r)rrArparsernamerrr_create_event_streamFsz#ResponseParser._create_event_stream)NN)rrr__doc__DEFAULT_ENCODINGr+rr(rCr9r7r8r<r;r:r[r`rXrerrrrr%s   0  r%cseZdZd"fdd ZddZddZfdd Zd d Zd d ZddZ ddZ ddZ ddZ e ddZe ddZe ddZe ddZe ddZe d d!ZeZeZeZZS)#BaseXMLResponseParserNcs"tt|||td|_dS)Nz{.*})superrhrrecompile _namespace_rer,rTrrrMs zBaseXMLResponseParser.__init__c Csi}|j}|j}|jdpd}|jdp.d}|jdrLt|tsL|g}|D]X}|D]F} || } | |kr|||| } qX| |kr||| } qXtd| qX| || <qP|S)Nrdkeyr/ flattenedzUnknown tag: %s) rnr/r=r>r?list _node_tagr[r$) rrrYrB key_shape value_shapeZkey_location_nameZvalue_location_nameZ keyval_nodeZ single_pairZtag_nameZkey_nameZval_namerrr _handle_mapRs"  z!BaseXMLResponseParser._handle_mapcCs|jd|jSNr)rlsubtag)rrYrrrrqgszBaseXMLResponseParser._node_tagcs.|jdrt|ts|g}tt|||S)Nro)r=r>r?rprirhr`)rrrYrmrrr`jsz"BaseXMLResponseParser._handle_listcCsi}|j}|jddr"||}||}|D]}||}d|jvs0|jdrTq0|||}||} | dur||| ||<q0|jdr0i} |jd} |j D],\} } |j | ddd| }| | |<q| | vr0| | ||<q0|S) NrDFlocation eventheaderZ xmlAttributerd:r) membersrEr>_get_error_root_build_name_to_xml_noder=_member_key_namer[attribitemsrlrvsplit)rrrYrBr{xml_dict member_namer^Zxml_nameZ member_nodeZattribsZ location_namernr/Znew_keyrrr_handle_structurets8          z'BaseXMLResponseParser._handle_structurecCs2||dkr.|D]}||dkr|Sq|S)NZ ErrorResponserLrq)r original_rootchildrrrr|s  z%BaseXMLResponseParser._get_error_rootcCsL|jdkr0|jdr0|jjd}|dur0|S|jd}|durH|S|S)Nrprord)rWr=r>r\)rrrZlist_member_serialized_nameZserialized_namerrrr~s z&BaseXMLResponseParser._member_key_namecCstt|tr||dSi}|D]N}||}||vrft||trT|||qn|||g||<q |||<q |S)Nr)r?rpr}rqr])rZ parent_noderr_rnrrrr}s   z-BaseXMLResponseParser._build_name_to_xml_nodec Csdz*tjt|jd}|||}Wn4ty^}ztd||fWYd}~n d}~00|S)N)targetencodingzTUnable to parse response (%s), invalid XML received. Further retries may succeed: %s)r XMLParser TreeBuilderrgfeedcloserr$)r xml_stringrcrooterrr_parse_xml_string_to_doms  z.BaseXMLResponseParser._parse_xml_string_to_domcCsB|D]4\}}t|r2||}||||<q|j||<q|Sr )rrpr}_replace_nodesr)rrBrnr/Zsub_dictrrrrs   z$BaseXMLResponseParser._replace_nodescCs|dkr dSdSdS)NtrueTFrrrrrrr_handle_booleansz%BaseXMLResponseParser._handle_booleancCst|Sr )floatrrrr _handle_floatsz#BaseXMLResponseParser._handle_floatcCs ||Sr r'rrrr_handle_timestampsz'BaseXMLResponseParser._handle_timestampcCst|Sr )intrrrr_handle_integersz%BaseXMLResponseParser._handle_integercCs|Sr rrrrr_handle_stringsz$BaseXMLResponseParser._handle_stringcCs ||Sr r)rrrr _handle_blobsz"BaseXMLResponseParser._handle_blob)NN)rrrrrtrqr`rr|r~r}rrr#rrrrrrZ_handle_characterZ_handle_doubleZ _handle_long __classcell__rrrmrrhLs2        rhc@s>eZdZddZddZddZddd Zd d Zd d ZdS) QueryParsercCs\|d}||}||}||d|vr>||dd|vrXd|di|d<|S)Nr1Errors RequestIdr4)rr}rrpop)rrAr xml_contentsrrBrrrr;s   zQueryParser._do_error_parsecCs|j||ddS)NFinject_metadata_parse_body_as_xmlrUrrrr:sz#QueryParser._do_modeled_error_parsecCs|j||ddS)NTrrrUrrrr< szQueryParser._do_parseTcCs^|d}||}i}|durJ|}d|jvr>||jd|}|||}|rZ||||S)Nr1Z resultWrapper)rr=_find_result_wrapped_shaper[_inject_response_metadata)rrArrrrrBstartrrrr s    zQueryParser._parse_body_as_xmlcCs||}||Sr )r})rZ element_nameZ xml_root_nodemappingrrrrs z&QueryParser._find_result_wrapped_shapecCsN||}|d}|durJ||}|D]\}}|j||<q.||d<dSNr4)r}r>rr)rrY inject_intor child_nodeZ sub_mappingrnr/rrrr s    z%QueryParser._inject_response_metadataN)T) rrrr;r:r<rrrrrrrrs  rcs,eZdZddZfddZddZZS)EC2QueryParsercCs.||}|d}|dur*d|ji|d<dS)NZ requestIdrr4)r}r>r)rrYrrrrrrr,s  z(EC2QueryParser._inject_response_metadatacs0tt|||}d|vr,d|di|d<|S)NZ RequestIDrr4)rirr;r)rrAroriginalrmrrr;2s  zEC2QueryParser._do_error_parsecCs@|D]6}||dkr|D]}||dkr|Sqq|S)NrrLr)rrrZ errors_childrrrr|Fs zEC2QueryParser._get_error_root)rrrrr;r|rrrrmrr*s rc@sDeZdZddZddZddZddZd d Zd d Zd dZ dS)BaseJSONParserc Cspi}|jr|}n\|j}|dur"dSi}|D]@}||}|jd|}||}|dur*||||||<q*|S)Nrd)Zis_document_typer{r=r>r[) rrr/ final_parsed member_shapesrr^Z json_nameZ raw_valuerrrrQs"  z BaseJSONParser._handle_structurec CsFi}|j}|j}|D](\}}|||}|||}|||<q|Sr )rnr/rr[) rrr/rBrrrsrnZ actual_keyZ actual_valuerrrrtgs   zBaseJSONParser._handle_mapcCs ||Sr rrarrrrqszBaseJSONParser._handle_blobcCs ||Sr rrarrrrtsz BaseJSONParser._handle_timestampcCs||d}dddid}|d|dd|dd<|d}|d |oTt|}|durd |vrx|d d d }||dd <|||d |S)Nr1rrJrIrKmessagerJrLr2Z__type#rIr0)_parse_body_as_jsonr>rMrsplitr)rrArr1errorZ response_codecoderrrr;ws    zBaseJSONParser._do_error_parsecCs d|vr|d|did<dS)Nx-amzn-requestidr4r) setdefault)rrBr0rrrrsz(BaseJSONParser._inject_response_metadatacCsD|siS||j}zt|}|WSty>d|iYS0dS)Nr)decodergjsonloads ValueError)r body_contentsr1original_parsedrrrrs   z"BaseJSONParser._parse_body_as_jsonN) rrrrrtrrr;rrrrrrrOs rc@s4eZdZddZddZddZddZd d Zd S) BaseEventStreamParsercCshi}|jdr@|dd}|j|}|rd|||||<n$||||j|||||j||S)Nr3r0z :event-type)r=r>r{r<_parse_non_payload_attrs_parse_payload)rrArrZ event_typeZ event_shaperrrr<s  zBaseEventStreamParser._do_parsec Cs|dd}|j|}|dur\||d}|||}d||d|dddi}n&d|dd d|dd ddi}|S) Nr0z:exception-typer1rLrJrrrHz :error-codez:error-message)r>r{_initial_body_parser[)rrArZexception_typeZexception_shaperr1rrrrr;s   z%BaseEventStreamParser._do_error_parsec Cs|jdr|D]l}||}|jdr|d}|jdkr@|}n.|jdkrX||j}n||} ||| }|||<dSq||d} ||| } || dS)NeventZ eventpayloadr1blobstring)r=r>rWrrgrr[r) rrArrrrdr^r1Z parsed_bodyZ raw_parser body_parsedrrrrs        z$BaseEventStreamParser._parse_payloadc CsZ|d}|D]H}||}|jdr ||vr ||}|jdkrL||d}|||<q dS)Nr0ry timestampg@@)r=r>rWr') rrArrrr0rdr^r/rrrrs  z.BaseEventStreamParser._parse_non_payload_attrscCs tddSNrrSrrrrrrsz)BaseEventStreamParser._initial_body_parseN)rrrr<r;rrrrrrrrs  rc@seZdZddZdS)EventStreamJSONParsercCs ||Sr rrrrrrsz)EventStreamJSONParser._initial_body_parseNrrrrrrrrrsrc@seZdZddZdS)EventStreamXMLParsercCs|stdS||SrurElementrrrrrrrs z(EventStreamXMLParser._initial_body_parseNrrrrrrsrc@s0eZdZeZddZddZddZddZd S) JSONParsercCsJi}|dur6|j}|r&||||}n||d|}|||d|S)Nr1r0)Zevent_stream_name_handle_event_stream_handle_json_bodyr)rrArrB event_namerrrr<szJSONParser._do_parsecCs||d|S)Nr1)rrUrrrr:sz"JSONParser._do_modeled_error_parsec Cs\|j|}|||}z |}Wnty@d}t|Yn0||j|}|||<|S)Nz,First event was not of type initial-response)r{reZget_initial_responserr$rpayload) rrArrZevent_stream_shapeZ event_streamr error_msgrBrrrrs    zJSONParser._handle_event_streamcCs||}|||Sr )rr[)rZraw_bodyrZ parsed_jsonrrrrs zJSONParser._handle_json_bodyN) rrrrr+r<r:rrrrrrrs   rc@sTeZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ dS)BaseRestParsercCs$i}|||d<|||||Sr)_populate_response_metadata_add_modeled_parserrArrrrrr<)s zBaseRestParser._do_parsecCs6|dur |S|j}||||||||||dSr )r{rr)rrArrrrrrr0sz!BaseRestParser._add_modeled_parsecCsi}|||||Sr )rrrrrr:8sz&BaseRestParser._do_modeled_error_parsecCsJi}|d}d|vr"|d|d<n$d|vrF|d|d<|dd|d<|S)Nr0rrx-amz-request-id x-amz-id-2rHostId)r>)rrArEr0rrrr=s z*BaseRestParser._populate_response_metadatac Csd|jvr|jd}||}|jdr>|||}|||<q|jdvrp|d}t|trf||j}|||<q||d}| ||||<n$||d}| ||} | | dS)Nrr3)rrr1) r=r>rerWr?bytesrrgrr[r) rrArrrZpayload_member_nameZ body_shaper1rrrrrrJs$           zBaseRestParser._parse_payloadc Cs|d}|D]}||}|jd}|dur0q q |dkrN|||d||<q |dkrh|||||<q |dkr |jd|} | |vr |||| ||<q dS)Nr0rxZ statusCoder2headerrd)r=r>r[_parse_header_map) rrArrrr0rdr^rx header_namerrrrbs(   z'BaseRestParser._parse_non_payload_attrscCsNi}|jdd}|D].}||r|t|d}||||<q|S)Nrdr)r=r>lowerrGlen)rrr0rBprefixrrdrrrrvsz BaseRestParser._parse_header_mapcCs tddSrrrrrrrsz"BaseRestParser._initial_body_parsecCs,|}t|r(t||j}t|}|Sr )r r-r.rrgrr)rrr/rBdecodedrrrrs  zBaseRestParser._handle_stringN) rrrr<rr:rrrrrrrrrrr's  rcs0eZdZeZddZfddZddZZS)RestJSONParsercCs ||Sr rrrrrrsz"RestJSONParser._initial_body_parsecs"tt|||}||||Sr )rirr;_inject_error_code)rrArrrmrrr;s zRestJSONParser._do_error_parsecCsr||d}d|dvrB|dd}|dd}||dd<n,d|vsRd|vrn|d|dd |dd<dS) Nr1zx-amzn-errortyper0rzrrLrIrr)rrr>)rrrAr1rrrrrs   z!RestJSONParser._inject_error_code) rrrrr+rr;rrrrrmrrs rcsDeZdZeZddZddZddZddZe fd d Z Z S) RestXMLParsercCs|stdS||Srurrrrrrs z!RestXMLParser._initial_body_parsec CsR|drHz ||WStyF}ztjdddWYd}~n d}~00||S)Nr1z2Exception caught when parsing error response body:T)exc_info)_parse_error_from_bodyr$r5r6_parse_error_from_http_status)rrArrrrrr;s zRestXMLParser._do_error_parsecCsHt|dtjjj|ddd|ddd|dddddS) Nr2rrHr0rr)rrrK)rMrrNrOrPr>rQrrrrs  z+RestXMLParser._parse_error_from_http_statuscCs|d}||}||}|||jdkr\||}|dd|dd||dSd|vrvd|di|d<ddddi}t|||S) Nr1rLrrrrKr4r)rr}rrwrrr)rrArrrBrEdefaultrrrrs         z$RestXMLParser._parse_error_from_bodycstt|||}|Sr )rirrrrmrrrszRestXMLParser._handle_string) rrrrr+rr;rrr#rrrrrmrrs r)Zec2queryrz rest-jsonzrest-xml)(rfrjr-rloggingZbotocore.compatrrrZbotocore.eventstreamrrZbotocore.utilsrrr r getLoggerrr5r&objectr rr# Exceptionr$r%rhrrrrrrrrrrrrrrr sBh *5%UN'kN