a
    
dE                     @   sj  d 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mZmZmZmZmZmZ dd	lmZ dd
lmZmZmZ ddlmZ ddlm Z m!Z!m"Z"m#Z#m$Z$ ddl%m&Z& ddl'm(Z(m)Z) erddl*m+Z+ e#,e-Z.e/dZ0dZ1dddZ2eG dd dZ3e$d>ee3 ee4 e4e4ee4 eee5 ee5 f dddZ6G dd de&Z7G dd de&Z8deee4 ddd d!Z9e5d"d#d$Z:e5d%d&d'Z;e5d(d)d*Z<de4dd+d,d-Z=dee>e4dd.d/d0Z?ee3e>ee4 d1d2d3Z@ee e4e8d4d5d6ZAdee4 e>ee d7d8d9ZBdee4 e>ee d7d:d;ZCG d<d= d=eZDdS )?z.Git LFS related type definitions and utilities    N)AbstractContextManager)	dataclass)ceil)getsize)Path)TYPE_CHECKINGBinaryIODictIterableListOptionalTuple)HTTPBasicAuth)ENDPOINTHF_HUB_ENABLE_HF_TRANSFERREPO_TYPES_URL_PREFIXES)get_session   )get_token_to_sendhf_raise_for_statushttp_backoffloggingvalidate_hf_hub_args)	TypedDict)sha256sha_fileobj)CommitOperationAddz^[0-9a-f]{40}$zlfs-multipart-uploadzapplication/vnd.git-lfs+json)AcceptzContent-Typec                   @   s`   e Zd ZU dZeed< eed< eed< eedddZ	eedd	d
Z
eedddZdS )
UploadInfoad  
    Dataclass holding required information to determine whether a blob
    should be uploaded to the hub using the LFS protocol or the regular protocol

    Args:
        sha256 (`bytes`):
            SHA256 hash of the blob
        size (`int`):
            Size in bytes of the blob
        sample (`bytes`):
            First 512 bytes of the blob
    r   sizesample)pathc                 C   s\   t |}t|d*}|dd d }t|}W d    n1 sD0    Y  | |||dS )Nrb   r   r   r    )r   ioopenpeekr   )clsr!   r   filer    sha r+   \/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/huggingface_hub/lfs.py	from_pathG   s
    &zUploadInfo.from_pathdatac                 C   s&   t | }| t||d d |dS )Nr#   )r   r    r   )r   digestlen)r(   r/   r*   r+   r+   r,   
from_bytesO   s    zUploadInfo.from_bytes)fileobjc                 C   sD   | d}|dtj t|}| }|dtj | |||dS )Nr#   r   r$   )readseekr%   SEEK_SETr   tell)r(   r3   r    r*   r   r+   r+   r,   from_fileobjT   s    
zUploadInfo.from_fileobjN)__name__
__module____qualname____doc__bytes__annotations__intclassmethodstrr-   r2   r   r8   r+   r+   r+   r,   r   4   s   
r   )upload_infostoken	repo_typerepo_idendpointreturnc           
      C   s   |dur|nt }d}|tv r$t| }| d| | d}t j|tdddgdd	 | D d
dtdt|phdd}t| | }|	dd}	t
|	tstddd	 |	D dd	 |	D fS )a  
    Requests the LFS batch endpoint to retrieve upload instructions

    Learn more: https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md

    Args:
        upload_infos (`Iterable` of `UploadInfo`):
            `UploadInfo` for the files that are being uploaded, typically obtained
            from `CommitOperationAdd.upload_info`
        repo_type (`str`):
            Type of the repo to upload to: `"model"`, `"dataset"` or `"space"`.
        repo_id (`str`):
            A namespace (user or an organization) and a repo name separated
            by a `/`.
        token (`str`, *optional*):
            An authentication token ( See https://huggingface.co/settings/tokens )

    Returns:
        `LfsBatchInfo`: 2-tuple:
            - First element is the list of upload instructions from the server
            - Second element is an list of errors, if any

    Raises:
        `ValueError`: If an argument is invalid or the server response is malformed

        `HTTPError`: If the server returned an error
    N /z.git/info/lfs/objects/batchuploadbasic	multipartc                 S   s   g | ]}|j  |jd qS )oidr   )r   hexr   ).0rJ   r+   r+   r,   
<listcomp>   s   z'post_lfs_batch_info.<locals>.<listcomp>r   )	operationZ	transfersobjectsZ	hash_algoZaccess_tokenT)headersjsonauthrS   zMalformed response from serverc                 S   s   g | ]}d |vrt |qS error)_validate_batch_actionsrP   objr+   r+   r,   rQ          c                 S   s   g | ]}d |v rt |qS rW   )_validate_batch_errorrZ   r+   r+   r,   rQ      r\   )r   r   r   postLFS_HEADERSr   r   r   rU   get
isinstancelist
ValueError)
rB   rC   rD   rE   rF   Z
url_prefixZ	batch_urlrespZ
batch_inforS   r+   r+   r,   post_lfs_batch_info^   s8    #

re   c                   @   s   e Zd ZU eed< eed< dS )PayloadPartT
partNumberetagN)r9   r:   r;   r?   r>   rA   r+   r+   r+   r,   rf      s   
rf   c                   @   s&   e Zd ZU dZeed< ee ed< dS )CompletionPayloadTz?Payload that will be sent to the Hub when uploading multi-part.rN   partsN)r9   r:   r;   r<   rA   r>   r   rf   r+   r+   r+   r,   ri      s   
ri   r   )rR   lfs_batch_actionrC   rG   c           	   	   C   sF  t | |d}|du r2td| j d dS |d d }t| |d d}|durdt| |di }|d}|durzt|}W n& ttfy   td	| d
Y n0 t	| |||d d nt
| |d d |dur0t| t j|d tdt|pdd| jj | jjdd}t| t| j d dS )a  
    Handles uploading a given object to the Hub with the LFS protocol.

    Can be a No-op if the content of the file is already present on the hub large file storage.

    Args:
        operation (`CommitOperationAdd`):
            The add operation triggering this upload.
        lfs_batch_action (`dict`):
            Upload instructions from the LFS batch endpoint for this object. See [`~utils.lfs.post_lfs_batch_info`] for
            more details.
        token (`str`, *optional*):
            A [user access token](https://hf.co/settings/tokens) to authenticate requests against the Hub

    Raises:
        - `ValueError` if `lfs_batch_action` is improperly formatted
        - `HTTPError` if the upload resulted in an error
    actionsNzContent of file z. is already present upstream - skipping uploadrJ   verifyheader
chunk_sizezTMalformed response from LFS batch endpoint: `chunk_size` should be an integer. Got 'z'.href)rR   rn   ro   
upload_url)rR   rq   USERT)usernamepasswordrM   )rV   rU   z: Upload successful)rY   r`   loggerdebugZpath_in_repo_validate_lfs_actionr?   rc   	TypeError_upload_multi_part_upload_single_partr   r^   r   r   upload_infor   rO   r   r   )	rR   rk   rC   rl   upload_actionverify_actionrn   ro   Zverify_respr+   r+   r,   
lfs_upload   s<    




r~   Z
lfs_actionc                 C   s:   t | dtr.| ddu s6t | dts6td| S ).validates response from the LFS batch endpointrp   rn   Nz"lfs_action is improperly formatted)ra   r`   rA   dictrc   r   r+   r+   r,   rw      s    rw   )lfs_batch_actionsc                 C   sp   t | dtr t | dts(td| di d}| di d}|dur\t| |durlt| | S )r   rN   r   z)lfs_batch_actions is improperly formattedrl   rJ   rm   N)ra   r`   rA   r?   rc   rw   )r   r|   r}   r+   r+   r,   rY      s     rY   )lfs_batch_errorc                 C   sh   t | dtr t | dts(td| d}t |tr\t |dtr\t |dtsdtd| S )r   rN   r   z'lfs_batch_error is improperly formattedrX   messagecode)ra   r`   rA   r?   rc   r   )r   
error_infor+   r+   r,   r]     s     
r]   )rR   rq   rG   c                 C   sF   | j dd&}td||d}t| W d   n1 s80    Y  dS )aZ  
    Uploads `fileobj` as a single PUT HTTP request (basic LFS transfer protocol)

    Args:
        upload_url (`str`):
            The URL to PUT the file to.
        fileobj:
            The file-like object holding the data to upload.

    Returns: `requests.Response`

    Raises: `requests.HTTPError` if the upload resulted in an error
    TZ	with_tqdmPUTr.   N)as_filer   r   )rR   rq   r3   responser+   r+   r,   rz     s    rz   )rR   rn   ro   rq   rG   c                 C   s   t || j|d}t}tr>t| jts>t| jts>td d}|rPt	| ||dnt
| ||d}t j|t|| jj td}t| dS )z@
    Uploads file using HF multipart LFS transfer protocol.
    )rn   r{   ro   zlhf_transfer is enabled but does not support uploading from bytes or BinaryIO, falling back to regular uploadF)rR   sorted_parts_urlsro   )rU   rT   N)_get_sorted_parts_urlsr{   r   ra   path_or_fileobjrA   r   warningswarn_upload_parts_hf_transfer_upload_parts_iterativelyr   r^   _get_completion_payloadr   rO   r_   r   )rR   rn   ro   rq   r   Zuse_hf_transferresponse_headersZcompletion_resr+   r+   r,   ry   (  s,    

ry   )rn   r{   ro   rG   c                 C   sN   dd t dd |  D dd dD }t|}|t|j| krJtd|S )Nc                 S   s   g | ]\}}|qS r+   r+   )rP   _rq   r+   r+   r,   rQ   L  s   z*_get_sorted_parts_urls.<locals>.<listcomp>c                 S   s2   g | ]*\}}|  rt|d krt|d|fqS )r   
   )isdigitr1   r?   )rP   Zpart_numrq   r+   r+   r,   rQ   O  s   c                 S   s   | d S Nr   r+   )tr+   r+   r,   <lambda>T  r\   z(_get_sorted_parts_urls.<locals>.<lambda>)keyz0Invalid server response to upload large LFS file)sorteditemsr1   r   r   rc   )rn   r{   ro   Zsorted_part_upload_urlsZ	num_partsr+   r+   r,   r   K  s    r   )r   rN   rG   c                 C   sf   g }t | D ]N\}}|d}|d u s.|dkrFtd| d|d  ||d |d q||dS )Nrh   rH   zInvalid etag (`z`) returned for part r   )rg   rh   )rN   rj   )	enumerater`   rc   append)r   rN   rj   Zpart_numberrn   rh   r+   r+   r,   r   ]  s    
r   )rR   r   ro   rG   c           	   
   C   s   g }| j ddv}t|D ]\\}}t||| |d2}td||d}t| ||j W d    q1 sl0    Y  qW d    n1 s0    Y  |S )NTr   )	seek_from
read_limitr   r.   )r   r   SliceFileObjr   r   r   rT   )	rR   r   ro   rT   r3   Zpart_idxZpart_upload_urlZfileobj_sliceZpart_upload_resr+   r+   r,   r   l  s    Jr   c              
   C   sx   zddl m} W n ty*   tdY n0 z|| j||ddddW S  tyr } ztd|W Y d }~n
d }~0 0 d S )	Nr   )multipart_uploadzFast uploading using 'hf_transfer' is enabled (HF_HUB_ENABLE_HF_TRANSFER=1) but 'hf_transfer' package is not available in your environment. Try `pip install hf_transfer`.         )	file_pathZ
parts_urlsro   Z	max_filesZparallel_failuresmax_retriesz~An error occurred while uploading using `hf_transfer`. Consider disabling HF_HUB_ENABLE_HF_TRANSFER for better error handling.)Zhf_transferr   ImportErrorrc   r   	ExceptionRuntimeError)rR   r   ro   r   er+   r+   r,   r   }  s*    
r   c                   @   sp   e Zd ZdZeeedddZdd Zdd Zded
ddZ	edddZ
ejfeeedddZdd ZdS )r   a  
    Utility context manager to read a *slice* of a seekable file-like object as a seekable, file-like object.

    This is NOT thread safe

    Inspired by stackoverflow.com/a/29838711/593036

    Credits to @julien-c

    Args:
        fileobj (`BinaryIO`):
            A file-like object to slice. MUST implement `tell()` and `seek()` (and `read()` of course).
            `fileobj` will be reset to its original position when exiting the context manager.
        seek_from (`int`):
            The start of the slice (offset from position 0 in bytes).
        read_limit (`int`):
            The maximum number of bytes to read from the slice.

    Attributes:
        previous_position (`int`):
            The previous position

    Examples:

    Reading 200 bytes with an offset of 128 bytes from a file (ie bytes 128 to 327):
    ```python
    >>> with open("path/to/file", "rb") as file:
    ...     with SliceFileObj(file, seek_from=128, read_limit=200) as fslice:
    ...         fslice.read(...)
    ```

    Reading a file in chunks of 512 bytes
    ```python
    >>> import os
    >>> chunk_size = 512
    >>> file_size = os.getsize("path/to/file")
    >>> with open("path/to/file", "rb") as file:
    ...     for chunk_idx in range(ceil(file_size / chunk_size)):
    ...         with SliceFileObj(file, seek_from=chunk_idx * chunk_size, read_limit=chunk_size) as fslice:
    ...             chunk = fslice.read(...)

    ```
    r3   r   r   c                 C   s   || _ || _|| _d S Nr   )selfr3   r   r   r+   r+   r,   __init__  s    zSliceFileObj.__init__c                 C   sF   | j  | _| j dtj}t| j|| j | _	| j | jt
j | S r   )r3   r7   _previous_positionr5   osSEEK_ENDminr   r   _lenr%   r6   )r   Zend_of_streamr+   r+   r,   	__enter__  s
    zSliceFileObj.__enter__c                 C   s   | j | jtj d S r   )r3   r5   r   r%   r6   )r   exc_type	exc_value	tracebackr+   r+   r,   __exit__  s    zSliceFileObj.__exit__nc                 C   sB   |   }|| jkrdS | j| }| j|dk r2|nt||}|S )Nr\   r   )r7   r   r3   r4   r   )r   r   posZremaining_amountr/   r+   r+   r,   r4     s    

zSliceFileObj.read)rG   c                 C   s   | j  | j S r   )r3   r7   r   r   r+   r+   r,   r7     s    zSliceFileObj.tell)offsetwhencerG   c                 C   s   | j }|| j }|tjtjfv rR|tjkr2|| n|| }t|t||}tj}n>|tjkr| j	 }t|| t||| }nt
d| d| j||| j  S )Nzwhence value z is not supported)r   r   r   r6   r   maxr   SEEK_CURr3   r7   rc   r5   )r   r   r   startendZcur_posr+   r+   r,   r5     s    


zSliceFileObj.seekc                 c   s   | j ddV  d S )Ni  @ r   )r4   r   r+   r+   r,   __iter__  s    zSliceFileObj.__iter__N)r   )r9   r:   r;   r<   r   r?   r   r   r   r4   r7   r   r6   r5   r   r+   r+   r+   r,   r     s   ,r   )N)Er<   r%   r   rer   
contextlibr   Zdataclassesr   mathr   os.pathr   pathlibr   typingr   r   r	   r
   r   r   r   Zrequests.authr   Zhuggingface_hub.constantsr   r   r   Zhuggingface_hub.utilsr   utilsr   r   r   r   r   Zutils._typingr   Z	utils.shar   r   Z_commit_apir   Z
get_loggerr9   ru   compileZ	OID_REGEXZLFS_MULTIPART_UPLOAD_COMMANDr_   r   rA   r   re   rf   ri   r~   rw   rY   r]   rz   r?   ry   r   r   r   r   r   r+   r+   r+   r,   <module>   sj   $

) H<
#

