a
    !f+                     @   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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ZG dd deZdd Zdd ZdS )zzBatch 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)make_exception)
Connectionc                       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 or None
    :param body: HTTP payload

    c                    s   t |tr(t|}d|d< t||d< |d u r4d}d||f g}|dd t| D  |d || d	|}t
jrt| |d	t ntt| j}||d	t d S )
Napplication/jsonContent-TypezContent-Length z%s %s HTTP/1.1c                 S   s   g | ]\}}d ||f qS )z%s: %s ).0keyvaluer   r   U/var/www/html/python-backend/venv/lib/python3.9/site-packages/gcloud/storage/batch.py
<listcomp>;   s   z0MIMEApplicationHTTP.__init__.<locals>.<listcomp>z
http)
isinstancedictjsondumpslenextendsorteditemsappendjoinsixPY2r   __init__r   superr	   )selfmethoduriheadersbodylinespayload
super_init	__class__r   r   r    3   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dZdS )	NoContentz*Emulate an HTTP '204 No Content' response.   N)r,   r-   r.   r/   statusr   r   r   r   r1   I   s   r1   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   getT   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 futureNr5   )r"   r   r   r   r   __getitem__d   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 futureNr5   )r"   r   r   r   r   r   __setitem__o   s    z_FutureDict.__setitem__)N)r,   r-   r.   r/   staticmethodr8   r9   r:   r   r   r   r   r4   N   s
   r4   c                       s\   e Zd ZdZdZ fddZ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:`gcloud.storage.client.Client`
    :param client: The client to use for making connections.
    i  c                    s$   t t|   || _g | _g | _d S N)r!   r<   r    _client	_requests_target_objects)r"   clientr*   r   r   r       s    zBatch.__init__c                 C   s\   t | j| jkrtd| j | j||||f t }| j| |durR||_t |fS )a  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 or :class:`NoneType`
        :param target_object: 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.

        :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   r?   _MAX_BATCH_SIZE
ValueErrorr   r4   r@   _propertiesr1   )r"   r#   urlr%   datatarget_objectresultr   r   r   _do_request   s    zBatch._do_requestc                 C   s   t | jdkrtdt }| jD ]$\}}}}t||||}|| q"tjrXt	 }n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   r?   rC   r   r	   attachr   PY3ioStringIOBytesIOr   flattengetvaluesplitr   _headers)r"   multir#   r$   r%   r&   
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\}}|\}}d|j  krPdk s`n |p\||f}q*|dur*||_q*|du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.   i,  )r   r@   rC   zipr3   rD   r   )r"   	responsesZexception_argsrG   Zsub_responseZresp_headersZsub_payloadr   r   r   _finish_futures   s    zBatch._finish_futuresc                 C   sL   |   \}}d| j }| jjjd|||d\}}tt||}| | |S )zSubmit a single `multipart/mixed` request w/ deferred requests.

        :rtype: list of tuples
        :returns: one ``(headers, payload)`` tuple per deferred request.
        z%s/batchPOST)rF   r%   )rY   ZAPI_BASE_URLr>   _connection_make_requestlist_unpack_batch_responser]   )r"   r%   r&   rE   responsecontentr\   r   r   r   finish   s    


zBatch.finishc                 C   s   | j jS )z"Return the topmost batch, or None.)r>   Zcurrent_batchr"   r   r   r   current   s    zBatch.currentc                 C   s   | j |  | S r=   )r>   Z_push_batchrf   r   r   r   	__enter__  s    zBatch.__enter__c                 C   s0   z|d u r|    W | j  n| j  0 d S r=   )re   r>   Z
_pop_batch)r"   exc_typeexc_valexc_tbr   r   r   __exit__  s    
zBatch.__exit__)r,   r-   r.   r/   rB   r    rI   rY   r]   re   rg   rh   rl   r0   r   r   r*   r   r<   ~   s   %r<   c                 C   sj   t |tjs|d}|d }t |tjs4|d}dd|d|g}tjrV| |S | |dS dS )zdConvert response, content -> (multipart) email.message.

    Helper for _unpack_batch_response.
    zutf-8zcontent-type    s   Content-Type: s   
MIME-Version: 1.0

N)r   r   binary_typeencoder   r   parsestrdecode)parserrc   rd   content_typeZfaux_messager   r   r   _generate_faux_mime_message  s    


rt   c                 c   s   t  }t|| |}t|jts&td|jD ]~}|jdd\}}|dd\}}}||}	|	j}
|	d }t|	j	}||d< t
|}|r|drt|
}
||
fV  q,d	S )
a|  Convert response, content -> [(headers, payload)].

    Creates a generator of tuples of emulating the responses to
    :meth:`httplib2.Http.request` (a pair of headers and payload).

    :type response: :class:`httplib2.Response`
    :param response: HTTP response / headers from a request.

    :type content: str
    :param content: Response payload with a batch response.
    zBad response:  not multi-part
rJ       r   r3   r
   N)r   rt   r   _payloadra   rC   rR   rp   r   rS   httplib2Response
startswithr   loads)rc   rd   rr   messagerU   Zstatus_linerestrX   r3   Zsub_messager(   ctypeZmsg_headersr%   r   r   r   rb   '  s     




rb   )r/   email.encodersr   email.generatorr   Zemail.mime.applicationr   Zemail.mime.multipartr   email.parserr   rM   r   ry   r   Zgcloud.exceptionsr   Zgcloud.storage.connectionr   r	   objectr1   r4   r<   rt   rb   r   r   r   r   <module>   s$   (0 