U
    ä«FcÁ&  ã                   @   s¬   d Z ddlZddlZddlmZ z(ddlmZ ddlm	Z	 ddl
mZ W n4 ek
r|   ddlZddlmZ ddlm	Z	 Y nX e e¡ZG dd„ deƒZG d	d
„ d
eƒZdS )zHTTP Client libraryé    Né   )Úhandle_error)Ú	urlencode)Ú	HTTPErrorc                   @   sH   e Zd ZdZdd„ Zedd„ ƒZedd„ ƒZedd	„ ƒZed
d„ ƒZ	dS )ÚResponsez$Holds the response from an API call.c                 C   s"   |  ¡ | _| ¡ | _| ¡ | _dS )z¨
        :param response: The return value from a open call
                         on a urllib.build_opener()
        :type response:  urllib response object
        N)ÚgetcodeÚ_status_codeÚreadÚ_bodyÚinfoÚ_headers)ÚselfÚresponse© r   ú=/tmp/pip-unpacked-wheel-itnlelph/python_http_client/client.pyÚ__init__   s    

zResponse.__init__c                 C   s   | j S )z;
        :return: integer, status code of API call
        )r   ©r   r   r   r   Ústatus_code!   s    zResponse.status_codec                 C   s   | j S )z0
        :return: response from the API
        )r
   r   r   r   r   Úbody(   s    zResponse.bodyc                 C   s   | j S )z3
        :return: dict of response headers
        )r   r   r   r   r   Úheaders/   s    zResponse.headersc                 C   s    | j rt | j  d¡¡S dS dS )z8
        :return: dict of response from the API
        úutf-8N)r   ÚjsonÚloadsÚdecoder   r   r   r   Úto_dict6   s    zResponse.to_dictN)
Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Úpropertyr   r   r   r   r   r   r   r   r      s   



r   c                   @   st   e Zd ZdZdddddhZdd	d
„Zdd„ Zdd„ Zdd„ Zddd„Z	ddd„Z
dd„ Zdd„ Zdd„ Zdd„ ZdS ) ÚClientz4Quickly and easily access any REST or REST-like API.ÚdeleteÚgetÚpatchÚpostÚputNFc                 C   s0   || _ |pi | _|| _|pg | _|| _|| _dS )a‰  
        :param host: Base URL for the api. (e.g. https://api.sendgrid.com)
        :type host:  string
        :param request_headers: A dictionary of the headers you want
                                applied on all calls
        :type request_headers: dictionary
        :param version: The version number of the API.
                        Subclass _build_versioned_url for custom behavior.
                        Or just pass the version as part of the URL
                        (e.g. client._("/v3"))
        :type version: integer
        :param url_path: A list of the url path segments
        :type url_path: list of strings
        N)ÚhostÚrequest_headersÚ_versionÚ	_url_pathÚappend_slashÚtimeout)r   r&   r'   ÚversionÚurl_pathr*   r+   r   r   r   r   G   s    

zClient.__init__c                 C   s   d  | jt| jƒ|¡S )zþSubclass this function for your own needs.
           Or just pass the version as part of the URL
           (e.g. client._('/v3'))
        :param url: URI portion of the full URL being requested
        :type url: string
        :return: string
        z{}/v{}{})Úformatr&   Ústrr(   )r   Úurlr   r   r   Ú_build_versioned_urle   s    zClient._build_versioned_urlc                 C   sˆ   d}d}|t | jƒk r4|d | j| ¡7 }|d7 }q| jrB|d7 }|rdtt| ¡ ƒdƒ}d ||¡}| jrv|  |¡}nd | j	|¡}|S )	z¹Build the final URL to be passed to urllib

        :param query_params: A dictionary of all the query parameters
        :type query_params: dictionary
        :return: string
        Ú r   z/{}r   ú/Tz{}?{}z{}{})
Úlenr)   r.   r*   r   ÚsortedÚitemsr(   r1   r&   )r   Úquery_paramsr0   ÚcountZ
url_valuesr   r   r   Ú
_build_urlo   s    
zClient._build_urlc                 C   s   | j  |¡ dS )z²Update the headers for the request

        :param request_headers: headers to set for the API call
        :type request_headers: dictionary
        :return: dictionary
        N)r'   Úupdate)r   r'   r   r   r   Ú_update_headersŠ   s    zClient._update_headersc                 C   s4   |r| j |g n| j }t| j| j| j|| j| jd�S )z‹Make a new Client object

        :param name: Name of the url segment
        :type name: string
        :return: A Client object
        )r&   r,   r'   r-   r*   r+   )r)   r    r&   r(   r'   r*   r+   )r   Únamer-   r   r   r   Ú_build_client“   s    ûzClient._build_clientc              
   C   sr   |p| j }z|j||d�W S  tk
rl } z4t|ƒ}d|_t dj| ¡ |j	|j
d�¡ |‚W 5 d}~X Y nX dS )a„  Make the API call and return the response. This is separated into
           it's own function, so we can mock it easily for testing.

        :param opener:
        :type opener:
        :param request: url payload to request
        :type request: urllib.Request object
        :param timeout: timeout value or None
        :type timeout: float
        :return: urllib response
        ©r+   Nú"{method} Response: {status} {body}©ÚmethodÚstatusr   )r+   Úopenr   r   Ú	__cause__Ú_loggerÚdebugr.   Ú
get_methodr   r   )r   ÚopenerÚrequestr+   ÚerrÚexcr   r   r   Ú_make_request¢   s    
ýzClient._make_requestc                 C   s
   |   |¡S )aD  Add variable values to the url.
           (e.g. /your/api/{variable_value}/call)
           Another example: if you have a Python reserved word, such as global,
           in your url, you must use this method.

        :param name: Name of the url segment
        :type name: string
        :return: Client object
        )r=   )r   r<   r   r   r   Ú_º   s    
zClient._c                    sL   |dkr‡fdd„}|S |ˆj kr>| ¡ ‰ d‡ ‡fdd„	}|S ˆ |¡S dS )aD  Dynamically add method calls to the url, then call a method.
           (e.g. client.name.name.method())
           You can also add a version number by using .version(<int>)

        :param name: Name of the url segment or method call
        :type name: string or integer if name == version
        :return: mixed
        r,   c                     s   | d ˆ _ ˆ  ¡ S )zŽ
                :param args: dict of settings
                :param kwargs: unused
                :return: string, version
                r   )r(   r=   )ÚargsÚkwargsr   r   r   Úget_versionÐ   s    
z'Client.__getattr__.<locals>.get_versionNc           	         s  |rˆ  |¡ | dkrd}nBdˆjkr@ˆjd dkr@|  d¡}nˆj dd¡ t | ¡ d¡}t ¡ }tjˆ 	|¡ˆj|d�}‡ fdd„|_
t djˆ | ¡ d	�¡ |jr¾t d
j|jd�¡ t dj|jd�¡ tˆj|||d�ƒ}t djˆ |j|jd�¡ |S )a…  Make the API call
                :param timeout: HTTP request timeout. Will be propagated to
                    urllib client
                :type timeout: float
                :param request_headers: HTTP headers. Will be merged into
                    current client object state
                :type request_headers: dict
                :param query_params: HTTP query parameters
                :type query_params: dict
                :param request_body: HTTP request body
                :type request_body: string or json-serializable object
                :param kwargs:
                :return: Response object
                NzContent-Typezapplication/jsonr   )r   Údatac                      s   ˆ S ©Nr   r   )rA   r   r   Ú<lambda>	  ó    z:Client.__getattr__.<locals>.http_request.<locals>.<lambda>z{method} Request: {url})rA   r0   zPAYLOAD: {data})rQ   zHEADERS: {headers})r   r>   r?   r@   )r;   r'   ÚencodeÚ
setdefaultr   ÚdumpsÚurllibÚbuild_openerÚRequestr9   rG   rE   rF   r.   Úget_full_urlrQ   r   r   rL   r   r   )	Úrequest_bodyr7   r'   r+   rM   rQ   rH   rI   r   ©rA   r   r   r   Úhttp_requestÞ   sT    

ÿÿ ÿýþÿÿÿýz(Client.__getattr__.<locals>.http_request)NNNN)ÚmethodsÚupperrM   )r   r<   rP   r^   r   r]   r   Ú__getattr__Æ   s    	
    üAzClient.__getattr__c                 C   s   | j S rR   ©Ú__dict__r   r   r   r   Ú__getstate__$  s    zClient.__getstate__c                 C   s
   || _ d S rR   rb   )r   Ústater   r   r   Ú__setstate__'  s    zClient.__setstate__)NNNFN)N)N)r   r   r   r   r_   r   r1   r9   r;   r=   rL   rM   ra   rd   rf   r   r   r   r   r    A   s"        ú

	

^r    )r   r   ÚloggingÚ
exceptionsr   Úurllib.requestrI   rX   Úurllib.parser   Úurllib.errorr   ÚImportErrorÚurllib2Ú	getLoggerr   rE   Úobjectr   r    r   r   r   r   Ú<module>   s   
-