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 )zSubclass 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 )	zBuild 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 )zUpdate 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 )zMake 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rt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   
-