a
    `/                     @   s(  d Z ddl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	 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mZmZmZmZmZmZmZmZmZmZmZmZmZ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"ej%Z%dd Z&dd Z'dd Z(dd Z)dd Z*dS )zVirtual bases classes for uploading media via Google APIs.

Supported here are:

* simple (media) uploads
* multipart uploads that contain both metadata and a small file as payload
* resumable uploads (with metadata as well)
    N)http_client)_async_resumable_media)_helpers)_upload)common)_CONTENT_TYPE_HEADER_CONTENT_RANGE_TEMPLATE_RANGE_UNKNOWN_TEMPLATE_EMPTY_RANGE_TEMPLATE_BOUNDARY_FORMAT_MULTIPART_SEP_CRLF_MULTIPART_BEGIN_RELATED_HEADER_BYTES_RANGE_RE_STREAM_ERROR_TEMPLATE_POST_PUT!_UPLOAD_CHECKSUM_MISMATCH_MESSAGE0_UPLOAD_METADATA_NO_APPROPRIATE_CHECKSUM_MESSAGEc                   @   sR   e Zd ZdZdddZedd Zdd Zed	d
 Z	edd Z
edd ZdS )
UploadBasea  Base class for upload helpers.

    Defines core shared behavior across different upload types.

    Args:
        upload_url (str): The URL where the content will be uploaded.
        headers (Optional[Mapping[str, str]]): Extra headers that should
            be sent with the request, e.g. headers for encrypted data.

    Attributes:
        upload_url (str): The URL where the content will be uploaded.
    Nc                 C   s,   || _ |d u ri }|| _d| _t | _d S )NF)
upload_url_headers	_finishedr   ZRetryStrategyZ_retry_strategy)selfr   headers r   Dlib/python3.9/site-packages/google/_async_resumable_media/_upload.py__init__I   s    zUploadBase.__init__c                 C   s   | j S )z2bool: Flag indicating if the upload has completed.)r   r   r   r   r   finishedQ   s    zUploadBase.finishedc                 C   s   d| _ t|tjf| j dS )a  Process the response from an HTTP request.

        This is everything that must be done after a request that doesn't
        require network I/O (or other I/O). This is based on the `sans-I/O`_
        philosophy.

        Args:
            response (object): The HTTP response object.

        Raises:
            ~google.resumable_media.common.InvalidResponse: If the status
                code is not 200.

        .. _sans-I/O: https://sans-io.readthedocs.io/
        TN)r   r   require_status_coder   OK_get_status_coder   responser   r   r   _process_responseV   s    zUploadBase._process_responsec                 C   s   t ddS )zAccess the status code from an HTTP response.

        Args:
            response (object): The HTTP response object.

        Raises:
            NotImplementedError: Always, since virtual.
        This implementation is virtual.NNotImplementedErrorr%   r   r   r   r#   k   s    
zUploadBase._get_status_codec                 C   s   t ddS )zAccess the headers from an HTTP response.

        Args:
            response (object): The HTTP response object.

        Raises:
            NotImplementedError: Always, since virtual.
        r'   Nr(   r*   r   r   r   _get_headersw   s    
zUploadBase._get_headersc                 C   s   t ddS )zAccess the response body from an HTTP response.

        Args:
            response (object): The HTTP response object.

        Raises:
            NotImplementedError: Always, since virtual.
        r'   Nr(   r*   r   r   r   	_get_body   s    
zUploadBase._get_body)N)__name__
__module____qualname____doc__r   propertyr    r&   staticmethodr#   r+   r,   r   r   r   r   r   ;   s   



r   c                   @   s"   e Zd ZdZdd ZdddZdS )SimpleUploada  Upload a resource to a Google API.

    A **simple** media upload sends no metadata and completes the upload
    in a single request.

    Args:
        upload_url (str): The URL where the content will be uploaded.
        headers (Optional[Mapping[str, str]]): Extra headers that should
            be sent with the request, e.g. headers for encrypted data.

    Attributes:
        upload_url (str): The URL where the content will be uploaded.
    c                 C   sB   | j rtdt|tjs(tdt||| jt< t	| j
|| jfS )a  Prepare the contents of an HTTP request.

        This is everything that must be done before a request that doesn't
        require network I/O (or other I/O). This is based on the `sans-I/O`_
        philosophy.

        .. note:

            This method will be used only once, so ``headers`` will be
            mutated by having a new key added to it.

        Args:
            data (bytes): The resource content to be uploaded.
            content_type (str): The content type for the request.

        Returns:
            Tuple[str, str, bytes, Mapping[str, str]]: The quadruple

              * HTTP verb for the request (always POST)
              * the URL for the request
              * the body of the request
              * headers for the request

        Raises:
            ValueError: If the current upload has already finished.
            TypeError: If ``data`` isn't bytes.

        .. _sans-I/O: https://sans-io.readthedocs.io/
         An upload can only be used once.`data` must be bytes, received)r    
ValueError
isinstancesixbinary_type	TypeErrortyper   r   r   r   )r   datacontent_typer   r   r   _prepare_request   s    
zSimpleUpload._prepare_requestNc                 C   s   t ddS )a  Transmit the resource to be uploaded.

        Args:
            transport (object): An object which can make authenticated
                requests.
            data (bytes): The resource content to be uploaded.
            content_type (str): The content type of the resource, e.g. a JPEG
                image has content type ``image/jpeg``.
            timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
                The number of seconds to wait for the server response.
                Depending on the retry strategy, a request may be repeated
                several times using the same timeout each time.
                Can also be passed as an `aiohttp.ClientTimeout` object.

        Raises:
            NotImplementedError: Always, since virtual.
        r'   Nr(   )r   	transportr<   r=   timeoutr   r   r   transmit   s    zSimpleUpload.transmit)N)r-   r.   r/   r0   r>   rA   r   r   r   r   r3      s   &r3   c                       s4   e Zd ZdZd	 fdd	Zdd Zd
ddZ  ZS )MultipartUploada3  Upload a resource with metadata to a Google API.

    A **multipart** upload sends both metadata and the resource in a single
    (multipart) request.

    Args:
        upload_url (str): The URL where the content will be uploaded.
        headers (Optional[Mapping[str, str]]): Extra headers that should
            be sent with the request, e.g. headers for encrypted data.
        checksum Optional([str]): The type of checksum to compute to verify
            the integrity of the object. The request metadata will be amended
            to include the computed value. Using this option will override a
            manually-set checksum value. Supported values are "md5", "crc32c"
            and None. The default is None.

    Attributes:
        upload_url (str): The URL where the content will be uploaded.
    Nc                    s   t t| j||d || _d S )Nr   )superrB   r   _checksum_type)r   r   r   checksum	__class__r   r   r      s    zMultipartUpload.__init__c           
      C   s   | j rtdt|tjs(tdt|t| j	}|rd|
| t| }t| j	}|||< t|||\}}t| d }	|	| jt< t| j|| jfS )aj  Prepare the contents of an HTTP request.

        This is everything that must be done before a request that doesn't
        require network I/O (or other I/O). This is based on the `sans-I/O`_
        philosophy.

        .. note:

            This method will be used only once, so ``headers`` will be
            mutated by having a new key added to it.

        Args:
            data (bytes): The resource content to be uploaded.
            metadata (Mapping[str, str]): The resource metadata, such as an
                ACL list.
            content_type (str): The content type of the resource, e.g. a JPEG
                image has content type ``image/jpeg``.

        Returns:
            Tuple[str, str, bytes, Mapping[str, str]]: The quadruple

              * HTTP verb for the request (always POST)
              * the URL for the request
              * the body of the request
              * headers for the request

        Raises:
            ValueError: If the current upload has already finished.
            TypeError: If ``data`` isn't bytes.

        .. _sans-I/O: https://sans-io.readthedocs.io/
        r4   r5      ")r    r6   r7   r8   r9   r:   r;   sync_helpersZ_get_checksum_objectrE   updateprepare_checksum_digestdigest_get_metadata_keyconstruct_multipart_requestr   r   r   r   r   )
r   r<   metadatar=   Zchecksum_objectZactual_checksummetadata_keycontentmultipart_boundaryZmultipart_content_typer   r   r   r>      s$    !

z MultipartUpload._prepare_requestc                 C   s   t ddS )aq  Transmit the resource to be uploaded.

        Args:
            transport (object): An object which can make authenticated
                requests.
            data (bytes): The resource content to be uploaded.
            metadata (Mapping[str, str]): The resource metadata, such as an
                ACL list.
            content_type (str): The content type of the resource, e.g. a JPEG
                image has content type ``image/jpeg``.
            timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
                The number of seconds to wait for the server response.
                Depending on the retry strategy, a request may be repeated
                several times using the same timeout each time.
                Can also be passed as an `aiohttp.ClientTimeout` object.

        Raises:
            NotImplementedError: Always, since virtual.
        r'   Nr(   )r   r?   r<   rP   r=   r@   r   r   r   rA   ,  s    zMultipartUpload.transmit)NN)N)r-   r.   r/   r0   r   r>   rA   __classcell__r   r   rG   r   rB      s   :rB   c                       s   e Zd ZdZd& fdd	Zedd Zedd Zed	d
 Zedd Z	edd Z
d'ddZdd Zd(ddZdd Zdd Zdd Zdd Zd)ddZd d! Zd"d# Zd$d% Z  ZS )*ResumableUploada  Initiate and fulfill a resumable upload to a Google API.

    A **resumable** upload sends an initial request with the resource metadata
    and then gets assigned an upload ID / upload URL to send bytes to.
    Using the upload URL, the upload is then done in chunks (determined by
    the user) until all bytes have been uploaded.

    Args:
        upload_url (str): The URL where the resumable upload will be initiated.
        chunk_size (int): The size of each chunk used to upload the resource.
        headers (Optional[Mapping[str, str]]): Extra headers that should
            be sent with the :meth:`initiate` request, e.g. headers for
            encrypted data. These **will not** be sent with
            :meth:`transmit_next_chunk` or :meth:`recover` requests.
        checksum Optional([str]): The type of checksum to compute to verify
            the integrity of the object. After the upload is complete, the
            server-computed checksum of the resulting object will be read
            and google.resumable_media.common.DataCorruption will be raised on
            a mismatch. The corrupted file will not be deleted from the remote
            host automatically. Supported values are "md5", "crc32c" and None.
            The default is None.

    Attributes:
        upload_url (str): The URL where the content will be uploaded.

    Raises:
        ValueError: If ``chunk_size`` is not a multiple of
            :data:`.UPLOAD_CHUNK_SIZE`.
    Nc                    sv   t t| j||d |tj dkr6tdtjd || _d | _d | _	d| _
d| _|| _d | _d | _d | _d| _d S )NrC   r   z{} KB must divide chunk sizei   F)rD   rU   r   r   ZUPLOAD_CHUNK_SIZEr6   format_chunk_size_stream_content_type_bytes_uploadedZ_bytes_checksummedrE   _checksum_object_total_bytes_resumable_url_invalid)r   r   
chunk_sizerF   r   rG   r   r   r   b  s"    zResumableUpload.__init__c                 C   s   | j S )zbool: Indicates if the upload is in an invalid state.

        This will occur if a call to :meth:`transmit_next_chunk` fails.
        To recover from such a failure, call :meth:`recover`.
        r^   r   r   r   r   invalidu  s    zResumableUpload.invalidc                 C   s   | j S )z8int: The size of each chunk used to upload the resource.)rW   r   r   r   r   r_   ~  s    zResumableUpload.chunk_sizec                 C   s   | j S )z;Optional[str]: The URL of the in-progress resumable upload.)r]   r   r   r   r   resumable_url  s    zResumableUpload.resumable_urlc                 C   s   | j S )z-int: Number of bytes that have been uploaded.)rZ   r   r   r   r   bytes_uploaded  s    zResumableUpload.bytes_uploadedc                 C   s   | j S )a  Optional[int]: The total number of bytes to be uploaded.

        If this upload is initiated (via :meth:`initiate`) with
        ``stream_final=True``, this value will be populated based on the size
        of the ``stream`` being uploaded. (By default ``stream_final=True``.)

        If this upload is initiated with ``stream_final=False``,
        :attr:`total_bytes` will be :data:`None` since it cannot be
        determined from the stream.
        )r\   r   r   r   r   total_bytes  s    zResumableUpload.total_bytesTc           	      C   s   | j durtd| dkr&td|| _|| _tdd|i}|durN|| _n|r\t|| _| jdurzd| j}||d< |	| j
 t|d	}t| j||fS )
a  Prepare the contents of HTTP request to initiate upload.

        This is everything that must be done before a request that doesn't
        require network I/O (or other I/O). This is based on the `sans-I/O`_
        philosophy.

        Args:
            stream (IO[bytes]): The stream (i.e. file-like object) that will
                be uploaded. The stream **must** be at the beginning (i.e.
                ``stream.tell() == 0``).
            metadata (Mapping[str, str]): The resource metadata, such as an
                ACL list.
            content_type (str): The content type of the resource, e.g. a JPEG
                image has content type ``image/jpeg``.
            total_bytes (Optional[int]): The total number of bytes to be
                uploaded. If specified, the upload size **will not** be
                determined from the stream (even if ``stream_final=True``).
            stream_final (Optional[bool]): Indicates if the ``stream`` is
                "final" (i.e. no more bytes will be added to it). In this case
                we determine the upload size from the size of the stream. If
                ``total_bytes`` is passed, this argument will be ignored.

        Returns:
            Tuple[str, str, bytes, Mapping[str, str]]: The quadruple

              * HTTP verb for the request (always POST)
              * the URL for the request
              * the body of the request
              * headers for the request

        Raises:
            ValueError: If the current upload has already been initiated.
            ValueError: If ``stream`` is not at the beginning.

        .. _sans-I/O: https://sans-io.readthedocs.io/
        Nz'This upload has already been initiated.r   zStream must be at beginning.zapplication/json; charset=UTF-8zx-upload-content-typez{:d}zx-upload-content-lengthutf-8)rb   r6   tellrX   rY   r   r\   get_total_bytesrV   rK   r   jsondumpsencoder   r   )	r   streamrP   r=   rd   stream_finalr   Zcontent_lengthpayloadr   r   r   _prepare_initiate_request  s&    '


z)ResumableUpload._prepare_initiate_requestc                 C   s0   t j|tjf| j| jd t |d| j| _dS )aV  Process the response from an HTTP request that initiated upload.

        This is everything that must be done after a request that doesn't
        require network I/O (or other I/O). This is based on the `sans-I/O`_
        philosophy.

        This method takes the URL from the ``Location`` header and stores it
        for future use. Within that URL, we assume the ``upload_id`` query
        parameter has been included, but we do not check.

        Args:
            response (object): The HTTP response object (need headers).

        .. _sans-I/O: https://sans-io.readthedocs.io/
        callbacklocationN)	r   r!   r   r"   r#   _make_invalidheader_requiredr+   r]   r$   r   r   r   _process_initiate_response  s    z*ResumableUpload._process_initiate_responsec                 C   s   t ddS )ah  Initiate a resumable upload.

        By default, this method assumes your ``stream`` is in a "final"
        state ready to transmit. However, ``stream_final=False`` can be used
        to indicate that the size of the resource is not known. This can happen
        if bytes are being dynamically fed into ``stream``, e.g. if the stream
        is attached to application logs.

        If ``stream_final=False`` is used, :attr:`chunk_size` bytes will be
        read from the stream every time :meth:`transmit_next_chunk` is called.
        If one of those reads produces strictly fewer bites than the chunk
        size, the upload will be concluded.

        Args:
            transport (object): An object which can make authenticated
                requests.
            stream (IO[bytes]): The stream (i.e. file-like object) that will
                be uploaded. The stream **must** be at the beginning (i.e.
                ``stream.tell() == 0``).
            metadata (Mapping[str, str]): The resource metadata, such as an
                ACL list.
            content_type (str): The content type of the resource, e.g. a JPEG
                image has content type ``image/jpeg``.
            total_bytes (Optional[int]): The total number of bytes to be
                uploaded. If specified, the upload size **will not** be
                determined from the stream (even if ``stream_final=True``).
            stream_final (Optional[bool]): Indicates if the ``stream`` is
                "final" (i.e. no more bytes will be added to it). In this case
                we determine the upload size from the size of the stream. If
                ``total_bytes`` is passed, this argument will be ignored.
            timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
                The number of seconds to wait for the server response.
                Depending on the retry strategy, a request may be repeated
                several times using the same timeout each time.
                Can also be passed as an `aiohttp.ClientTimeout` object.

        Raises:
            NotImplementedError: Always, since virtual.
        r'   Nr(   )r   r?   rk   rP   r=   rd   rl   r@   r   r   r   initiate  s    1zResumableUpload.initiatec                 C   s   | j rtd| jrtd| jdu r.tdt| j| j| j\}}}|| jkrft	
|| j}t|| || t| jtj|i}t| j||fS )a  Prepare the contents of HTTP request to upload a chunk.

        This is everything that must be done before a request that doesn't
        require network I/O. This is based on the `sans-I/O`_ philosophy.

        For the time being, this **does require** some form of I/O to read
        a chunk from ``stream`` (via :func:`get_next_chunk`). However, this
        will (almost) certainly not be network I/O.

        Returns:
            Tuple[str, str, bytes, Mapping[str, str]]: The quadruple

              * HTTP verb for the request (always PUT)
              * the URL for the request
              * the body of the request
              * headers for the request

            The headers **do not** incorporate the ``_headers`` on the
            current instance.

        Raises:
            ValueError: If the current upload has finished.
            ValueError: If the current upload is in an invalid state.
            ValueError: If the current upload has not been initiated.
            ValueError: If the location in the stream (i.e. ``stream.tell()``)
                does not agree with ``bytes_uploaded``.

        .. _sans-I/O: https://sans-io.readthedocs.io/
        zUpload has finished.z;Upload is in an invalid state. To recover call `recover()`.Nz_This upload has not been initiated. Please call initiate() before beginning to transmit chunks.)r    r6   ra   rb   get_next_chunkrX   rW   r\   rc   r   rV   Z_update_checksumr   rY   r   CONTENT_RANGE_HEADERr   )r   
start_byterm   content_rangemsgr   r   r   r   r>   (  s*    


z ResumableUpload._prepare_requestc                 C   s
   d| _ dS )zSimple setter for ``invalid``.

        This is intended to be passed along as a callback to helpers that
        raise an exception so they can mark this instance as invalid before
        raising.
        TNr`   r   r   r   r   rr   a  s    zResumableUpload._make_invalidc                    s   t j|tjtjf| j| jd}|tjkrL| j| | _d| _	| 
|I dH  nVt j|t j| j| jd}t|}|du r|   t|d|dt|dd | _dS )a  Process the response from an HTTP request.

        This is everything that must be done after a request that doesn't
        require network I/O (or other I/O). This is based on the `sans-I/O`_
        philosophy.

        Args:
            response (object): The HTTP response object.
            bytes_sent (int): The number of bytes sent in the request that
                ``response`` was returned for.

        Raises:
            ~google.resumable_media.common.InvalidResponse: If the status
                code is 308 and the ``range`` header is not of the form
                ``bytes 0-{end}``.
            ~google.resumable_media.common.InvalidResponse: If the status
                code is not 200 or 308.

        .. _sans-I/O: https://sans-io.readthedocs.io/
        ro   TNUnexpected "range" header*Expected to be of the form "bytes=0-{end}"end_byte   )r   r!   r   r"   r   PERMANENT_REDIRECTr#   rr   rZ   r   _validate_checksumrs   RANGE_HEADERr+   r   matchr   InvalidResponseintgroup)r   r%   Z
bytes_sentZstatus_codebytes_ranger   r   r   r   r&   j  s4    

	
z!ResumableUpload._process_responsec                    s   | j du rdS t| j }| I dH }||}|du rTt|t|| 	|t
| j }||krt|t| j  ||dS )aQ  Check the computed checksum, if any, against the response headers.
        Args:
            response (object): The HTTP response object.
        Raises:
            ~google.resumable_media.common.DataCorruption: If the checksum
            computed locally and the checksum reported by the remote host do
            not match.
        N)rE   rJ   rN   rh   getr   r   r   rV   r+   rL   r[   rM   ZDataCorruptionr   upper)r   r%   rQ   rP   Zremote_checksumZlocal_checksumr   r   r   r     s*    	

z"ResumableUpload._validate_checksumc                 C   s   t ddS )a  Transmit the next chunk of the resource to be uploaded.

        If the current upload was initiated with ``stream_final=False``,
        this method will dynamically determine if the upload has completed.
        The upload will be considered complete if the stream produces
        fewer than :attr:`chunk_size` bytes when a chunk is read from it.

        Args:
            transport (object): An object which can make authenticated
                requests.
            timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
                The number of seconds to wait for the server response.
                Depending on the retry strategy, a request may be repeated
                several times using the same timeout each time.
                Can also be passed as an `aiohttp.ClientTimeout` object.

        Raises:
            NotImplementedError: Always, since virtual.
        r'   Nr(   )r   r?   r@   r   r   r   transmit_next_chunk  s    z#ResumableUpload.transmit_next_chunkc                 C   s&   | j stdtjdi}t| jd|fS )a  Prepare the contents of HTTP request to recover from failure.

        This is everything that must be done before a request that doesn't
        require network I/O. This is based on the `sans-I/O`_ philosophy.

        We assume that the :attr:`resumable_url` is set (i.e. the only way
        the upload can end up :attr:`invalid` is if it has been initiated.

        Returns:
            Tuple[str, str, NoneType, Mapping[str, str]]: The quadruple

              * HTTP verb for the request (always PUT)
              * the URL for the request
              * the body of the request (always :data:`None`)
              * headers for the request

            The headers **do not** incorporate the ``_headers`` on the
            current instance.

        Raises:
            ValueError: If the current upload is not in an invalid state.

        .. _sans-I/O: https://sans-io.readthedocs.io/
        z3Upload is not in invalid state, no need to recover.z	bytes */*N)ra   r6   r   rw   r   rb   )r   r   r   r   r   _prepare_recover_request  s    
z(ResumableUpload._prepare_recover_requestc                 C   s   t |tjf| j | |}t j|v rj|t j }t|}|du rTt	
|d|dt|dd | _nd| _| j| j d| _dS )a  Process the response from an HTTP request to recover from failure.

        This is everything that must be done after a request that doesn't
        require network I/O (or other I/O). This is based on the `sans-I/O`_
        philosophy.

        Args:
            response (object): The HTTP response object.

        Raises:
            ~google.resumable_media.common.InvalidResponse: If the status
                code is not 308.
            ~google.resumable_media.common.InvalidResponse: If the status
                code is 308 and the ``range`` header is not of the form
                ``bytes 0-{end}``.

        .. _sans-I/O: https://sans-io.readthedocs.io/
        Nr{   r|   r}   r~   r   F)r   r!   r   r   r#   r+   r   r   r   r   r   r   r   rZ   rX   seekr^   )r   r%   r   r   r   r   r   r   _process_recover_response  s(    



z)ResumableUpload._process_recover_responsec                 C   s   t ddS )a!  Recover from a failure.

        This method should be used when a :class:`ResumableUpload` is in an
        :attr:`~ResumableUpload.invalid` state due to a request failure.

        This will verify the progress with the server and make sure the
        current upload is in a valid state before :meth:`transmit_next_chunk`
        can be used again.

        Args:
            transport (object): An object which can make authenticated
                requests.

        Raises:
            NotImplementedError: Always, since virtual.
        r'   Nr(   )r   r?   r   r   r   recover$  s    zResumableUpload.recover)NN)NT)NTN)N)r-   r.   r/   r0   r   r1   ra   r_   rb   rc   rd   rn   rt   ru   r>   rr   r&   r   r   r   r   r   rT   r   r   rG   r   rU   C  s6   




 
@    
39	;
+rU   c                  C   s    t tj} t| }|dS )zGet a random boundary for a multipart request.

    Returns:
        bytes: The boundary used to separate parts of a multipart request.
    re   )randomZ	randrangesysmaxsizer   rV   rj   )Z
random_intboundaryr   r   r   get_boundary8  s    
r   c                 C   sh   t  }t|d}|d}t| }|t | t | t d | t t |  t | t }||fS )a  Construct a multipart request body.

    Args:
        data (bytes): The resource content (UTF-8 encoded as bytes)
            to be uploaded.
        metadata (Mapping[str, str]): The resource metadata, such as an
            ACL list.
        content_type (str): The content type of the resource, e.g. a JPEG
            image has content type ``image/jpeg``.

    Returns:
        Tuple[bytes, bytes]: The multipart request body and the boundary used
        between each part.
    re   s   content-type: )r   rh   ri   rj   r   r   r   )r<   rP   r=   rS   Z
json_bytesZboundary_seprR   r   r   r   rO   E  sB    
	
rO   c                 C   s,   |   }| dtj |   }| | |S )zDetermine the total number of bytes in a stream.

    Args:
       stream (IO[bytes]): The stream (i.e. file-like object).

    Returns:
        int: The number of bytes.
    r   )rf   r   osSEEK_END)rk   Zcurrent_positionZend_positionr   r   r   rg   n  s
    	
rg   c                 C   s   |   }|dur<|| |  kr(dkr<n n| || }n
| |}|   d }t|}|du rt||k r|d }n*|dkr|dkrtdn|dkrtdt|||}|||fS )a  Get a chunk from an I/O stream.

    The ``stream`` may have fewer bytes remaining than ``chunk_size``
    so it may not always be the case that
    ``end_byte == start_byte + chunk_size - 1``.

    Args:
        stream (IO[bytes]): The stream (i.e. file-like object).
        chunk_size (int): The size of the chunk to be read from the ``stream``.
        total_bytes (Optional[int]): The (expected) total number of bytes
            in the ``stream``.

    Returns:
        Tuple[int, bytes, str]: Triple of:

          * the start byte index
          * the content in between the start and end bytes (inclusive)
          * content range header for the chunk (slice) that has been read

    Raises:
        ValueError: If ``total_bytes == 0`` but ``stream.read()`` yields
            non-empty content.
        ValueError: If there is no data left to consume. This corresponds
            exactly to the case ``end_byte < start_byte``, which can only
            occur if ``end_byte == start_byte - 1``.
    Nr   r~   z:Stream specified as empty, but produced non-empty content.z;Stream is already exhausted. There is no content remaining.)rf   readlenr6   get_content_range)rk   r_   rd   rx   rm   r}   Znum_bytes_readry   r   r   r   rv     s(    $

rv   c                 C   s8   |du rt | |S || k r&t|S t| ||S dS )a  Convert start, end and total into content range header.

    If ``total_bytes`` is not known, uses "bytes {start}-{end}/*".
    If we are dealing with an empty range (i.e. ``end_byte < start_byte``)
    then "bytes */{total}" is used.

    This function **ASSUMES** that if the size is not known, the caller will
    not also pass an empty range.

    Args:
        start_byte (int): The start (inclusive) of the byte range.
        end_byte (int): The end (inclusive) of the byte range.
        total_bytes (Optional[int]): The number of bytes in the byte
            range (if known).

    Returns:
        str: The content range header.
    N)r	   rV   r
   r   )rx   r}   rd   r   r   r   r     s
    
r   )+r0   rh   r   r   r   r8   Z	six.movesr   googler   Zgoogle._async_resumable_mediar   Zgoogle.resumable_mediarJ   r   Zsync_uploadr   Zgoogle.resumable_media._uploadr   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   objectr   r3   rB   rU   r   rO   rg   rv   r   r   r   r   r   <module>   s0   
DUJi   x)9