U
    8b,                     @   s   d Z ddlmZ ddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlZddlZddlZddlmZ dd	lmZ dd
lmZ ddlmZ G dd deZG dd deZG dd dejZG dd deZdd Zdd ZdS )zyBatch updates / deletes of storage buckets / blobs.

See https://cloud.google.com/storage/docs/json_api/v1/how-tos/batch
    )encode_noop)	Generator)MIMEApplication)MIMEMultipart)ParserN)_helpers)
exceptions)
Connection)_DEFAULT_TIMEOUTc                       s    e Zd ZdZ fddZ  ZS )MIMEApplicationHTTPa?  MIME type for ``application/http``.

    Constructs payload from headers and body

    :type method: str
    :param method: HTTP method

    :type uri: str
    :param uri: URI for HTTP request

    :type headers:  dict
    :param headers: HTTP headers

    :type body: str
    :param body: (Optional) HTTP payload

    c                    s   t |tr(t|}d|d< t||d< |d kr4d}d||f g}|dd t| D  |d || d	|}t
 |d	t d S )
Nzapplication/jsonzContent-TypezContent-Length z%s %s HTTP/1.1c                 S   s   g | ]\}}d ||f qS )z%s: %s ).0keyvaluer   r   S/var/www/flask_sites/venv/lib/python3.8/site-packages/google/cloud/storage/batch.py
<listcomp>>   s     z0MIMEApplicationHTTP.__init__.<locals>.<listcomp>z
http)
isinstancedictjsondumpslenextendsorteditemsappendjoinsuper__init__r   )selfmethoduriheadersbodylinespayload	__class__r   r   r   5   s    




zMIMEApplicationHTTP.__init__)__name__
__module____qualname____doc__r   __classcell__r   r   r'   r   r   "   s   r   c                   @   s.   e Zd ZdZed	ddZdd Zdd ZdS )
_FutureDictzvClass to hold a future value for a deferred request.

    Used by for requests that get sent in a :class:`Batch`.
    Nc                 C   s   t d| |f dS )a,  Stand-in for dict.get.

        :type key: object
        :param key: Hashable dictionary key.

        :type default: object
        :param default: Fallback value to dict.get.

        :raises: :class:`KeyError` always since the future is intended to fail
                 as a dictionary.
        z&Cannot get(%r, default=%r) on a futureNKeyError)r   defaultr   r   r   getL   s    z_FutureDict.getc                 C   s   t d|f dS )zStand-in for dict[key].

        :type key: object
        :param key: Hashable dictionary key.

        :raises: :class:`KeyError` always since the future is intended to fail
                 as a dictionary.
        z Cannot get item %r from a futureNr/   )r    r   r   r   r   __getitem__[   s    	z_FutureDict.__getitem__c                 C   s   t d||f dS )a'  Stand-in for dict[key] = value.

        :type key: object
        :param key: Hashable dictionary key.

        :type value: object
        :param value: Dictionary value.

        :raises: :class:`KeyError` always since the future is intended to fail
                 as a dictionary.
        zCannot set %r -> %r on a futureNr/   )r    r   r   r   r   r   __setitem__f   s    z_FutureDict.__setitem__)N)r)   r*   r+   r,   staticmethodr2   r3   r4   r   r   r   r   r.   F   s
   r.   c                       s4   e Zd ZdZ fddZdd Zedd Z  ZS )_FutureResponsezEReponse that returns a placeholder dictionary for a batched requests.c                    s   t t|   || _d| _d S )N   )r   r6   r   _future_dictstatus_code)r    Zfuture_dictr'   r   r   r   x   s    z_FutureResponse.__init__c                 C   s   | j S Nr8   r    r   r   r   r   }   s    z_FutureResponse.jsonc                 C   s   | j S r:   r;   r<   r   r   r   content   s    z_FutureResponse.content)	r)   r*   r+   r,   r   r   propertyr=   r-   r   r   r'   r   r6   u   s
   r6   c                       s`   e Zd ZdZdZ fddZefddZdd Zd	d
 Z	dd Z
dd Zdd Zdd Z  ZS )BatchzProxy an underlying connection, batching up change operations.

    :type client: :class:`google.cloud.storage.client.Client`
    :param client: The client to use for making connections.
    i  c                    s6   |j j}|j j}tt| j|||d g | _g | _d S )N)client_infoapi_endpoint)_connectionAPI_BASE_URLZ_client_infor   r?   r   	_requests_target_objects)r    clientrA   r@   r'   r   r   r      s    
  zBatch.__init__c                 C   s\   t | j| jkrtd| j | j|||||f t }| j| |dk	rT||_t|S )au  Override Connection:  defer actual HTTP request.

        Only allow up to ``_MAX_BATCH_SIZE`` requests to be deferred.

        :type method: str
        :param method: The HTTP method to use in the request.

        :type url: str
        :param url: The URL to send the request to.

        :type headers: dict
        :param headers: A dictionary of HTTP headers to send with the request.

        :type data: str
        :param data: The data to send as the body of the request.

        :type target_object: object
        :param target_object:
            (Optional) This allows us to enable custom behavior in our batch
            connection. Here we defer an HTTP request and complete
            initialization of the object at a later time.

        :type timeout: float or tuple
        :param timeout:
            (Optional) The amount of time, in seconds, to wait
            for the server response.  See: :ref:`configuring_timeouts`

        :rtype: tuple of ``response`` (a dictionary of sorts)
                and ``content`` (a string).
        :returns: The HTTP response object and the content of the response.
        z#Too many deferred requests (max %d)N)	r   rD   _MAX_BATCH_SIZE
ValueErrorr   r.   rE   _propertiesr6   )r    r!   urlr#   datatarget_objecttimeoutresultr   r   r   _do_request   s    "zBatch._do_requestc                 C   s   t | jdkrtdt }t}| jD ]*\}}}}}t||||}|| |}q&t }	t	|	dd}
|

| |	 }|dd\}}t|j||fS )zPrepares headers and body for a batch request.

        :rtype: tuple (dict, str)
        :returns: The pair of headers and body of the batch request to be sent.
        :raises: :class:`ValueError` if no requests have been deferred.
        r   zNo deferred requestsFz

   )r   rD   rH   r   r
   r   attachioStringIOr   flattengetvaluesplitr   _headers)r    ZmultirM   r!   r"   r#   r$   _timeout
subrequestbuf	generatorr&   _r   r   r   _prepare_batch_request   s    

zBatch._prepare_batch_requestc              	   C   s   d}t | jt |krtdt| j|D ]^\}}d|j  krHdk sTn |pP|}q*|dk	r*z| |_W q* tk
r   |j|_Y q*X q*|dk	rt	|dS )a6  Apply all the batch responses to the futures created.

        :type responses: list of (headers, payload) tuples.
        :param responses: List of headers and payloads from each response in
                          the batch.

        :raises: :class:`ValueError` if no requests have been deferred.
        Nz&Expected a response for every request.   ,  )
r   rE   rH   zipr9   r   rI   r=   r   from_http_response)r    	responsesZexception_argsrL   subresponser   r   r   _finish_futures   s    
zBatch._finish_futuresc                 C   sl   |   \}}}d| j }| jjjd||||d}d|j  krFdk sRn t|tt	|}| 
| |S )zSubmit a single `multipart/mixed` request with deferred requests.

        :rtype: list of tuples
        :returns: one ``(headers, payload)`` tuple per deferred request.
        z%s/batch/storage/v1POST)rK   r#   rM   r^   r_   )r]   rC   _clientZ_base_connection_make_requestr9   r   ra   list_unpack_batch_responserd   )r    r#   r$   rM   rJ   responserb   r   r   r   finish   s    
    

zBatch.finishc                 C   s   | j jS )z"Return the topmost batch, or None.)rf   Zcurrent_batchr<   r   r   r   current  s    zBatch.currentc                 C   s   | j |  | S r:   )rf   Z_push_batchr<   r   r   r   	__enter__  s    zBatch.__enter__c                 C   s&   z|d kr|   W 5 | j   X d S r:   )rf   Z
_pop_batchrk   )r    exc_typeexc_valexc_tbr   r   r   __exit__  s    zBatch.__exit__)r)   r*   r+   r,   rG   r   r
   rO   r]   rd   rk   rl   rm   rq   r-   r   r   r'   r   r?      s   

-r?   c                 C   s8   t |jdd}dd|d|jg}| |dS )zdConvert response, content -> (multipart) email.message.

    Helper for _unpack_batch_response.
    zcontent-typer       s   Content-Type: s   
MIME-Version: 1.0

utf-8)r   	_to_bytesr#   r2   r   r=   parsestrdecode)parserrj   content_typeZfaux_messager   r   r   _generate_faux_mime_message%  s
    ry   c                 c   s   t  }t|| }t|jts$td|jD ]}|jdd\}}|dd\}}}||}|j}	t|j	}
|

d}t }tjdd|d	 |_t||_|j|
 |	d
|_|V  q*dS )a  Convert requests.Response -> [(headers, payload)].

    Creates a generator of tuples of emulating the responses to
    :meth:`requests.Session.request`.

    :type response: :class:`requests.Response`
    :param response: HTTP response / headers from a request.
    zBad response:  not multi-part
rP       z
Content-IDZBATCHzcontentid://{})r!   rJ   rs   N)r   ry   r   _payloadrh   rH   rV   ru   r   rW   r2   requestsResponseRequestformatpreparerequestintr9   r#   updateencode_content)rj   rw   messagerY   Zstatus_linerestr\   statusZsub_messager&   Zmsg_headersZ
content_idrc   r   r   r   ri   6  s(    	




 
ri   )r,   email.encodersr   email.generatorr   Zemail.mime.applicationr   Zemail.mime.multipartr   email.parserr   rR   r   r~   Zgoogle.cloudr   r   Zgoogle.cloud.storage._httpr	   Zgoogle.cloud.storage.constantsr
   r   objectr.   r   r6   r?   ry   ri   r   r   r   r   <module>   s&   $/ !