U
    di|B                     @   s  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mZmZmZmZmZmZ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" d
dl#m$Z$ d
dl%m&Z&m'Z' d
dl(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e4 eee4e4f  eee4  eee5 ee5 ee4 f d	ddZ6G dd deZ7G dd deZ8d<deee4 eee4e4f  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.d/Z?ee3e>ee4 d0d1d2Z@ee e4e8d3d4d5ZAdee4 e>ee d6d7d8ZBdee4 e>ee d6d9d:ZCdS )=z.Git LFS related type definitions and utilities    N)	dataclass)ceil)getsize)Path)TYPE_CHECKINGBinaryIODictIterableListOptionalTuple	TypedDict)unquote)	constants   )build_hf_headersfix_hf_endpoint_in_urlget_sessionhf_raise_for_statushttp_backoffloggingtqdmvalidate_hf_hub_args)SliceFileObj)sha256sha_fileobj)is_tqdm_disabled)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   sH   t |}t|d }|dd d }t|}W 5 Q R X | |||dS )Nrb   r    r   r!   )r   ioopenpeekr   )clsr"   r    filer!   sha r,   7/tmp/pip-unpacked-wheel-ohruig0i/huggingface_hub/lfs.py	from_pathO   s
    zUploadInfo.from_pathdatac                 C   s&   t | }| t||d d |dS )Nr$   )r    r!   r   )r   digestlen)r)   r0   r+   r,   r,   r-   
from_bytesW   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)   r4   r!   r+   r    r,   r,   r-   from_fileobj\   s    
zUploadInfo.from_fileobjN)__name__
__module____qualname____doc__bytes__annotations__intclassmethodstrr.   r3   r   r9   r,   r,   r,   r-   r   <   s   
r   )	upload_infostoken	repo_typerepo_idrevisionendpointheaders	transfersreturnc                 C   s  |dk	r|nt j}d}|t jkr*t j| }| d| | d}	d|dk	rL|nddgdd	 | D d
d}
|dk	r~dt|i|
d< tt|d|pi }t j|	||
d}t| |	 }|
dd}t|tstd|
d}t|tr|n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 `/`.
        revision (`str`, *optional*):
            The git revision to upload to.
        headers (`dict`, *optional*):
            Additional headers to include in the request
        transfers (`list`, *optional*):
            List of transfer methods to use. Defaults to ["basic", "multipart"].

    Returns:
        `LfsBatchInfo`: 3-tuple:
            - First element is the list of upload instructions from the server
            - Second element is a list of errors, if any
            - Third element is the chosen transfer adapter if provided by the server (e.g. "basic", "multipart", "xet")

    Raises:
        [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
            If an argument is invalid or the server response is malformed.
        [`HTTPError`](https://requests.readthedocs.io/en/latest/api/#requests.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    ).0rN   r,   r,   r-   
<listcomp>   s   z'post_lfs_batch_info.<locals>.<listcomp>r   )	operationrJ   objectsZ	hash_algonameref)rD   rI   jsonrW   zMalformed response from serverZtransferc                 S   s   g | ]}d |krt |qS error)_validate_batch_actionsrT   objr,   r,   r-   rU      s      c                 S   s   g | ]}d |krt |qS r\   )_validate_batch_errorr_   r,   r,   r-   rU      s      )r   ZENDPOINTZREPO_TYPES_URL_PREFIXESr   LFS_HEADERSr   r   postr   r[   get
isinstancelist
ValueErrorrB   )rC   rD   rE   rF   rG   rH   rI   rJ   Z
url_prefixZ	batch_urlpayloadrespZ
batch_inforW   Zchosen_transferr,   r,   r-   post_lfs_batch_infof   s<    ,



rj   c                   @   s   e Zd ZU eed< eed< dS )PayloadPartT
partNumberetagN)r:   r;   r<   r@   r?   rB   r,   r,   r,   r-   rk      s   
rk   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.rR   partsN)r:   r;   r<   r=   rB   r?   r
   rk   r,   r,   r,   r-   rn      s   
rn   r   )rV   lfs_batch_actionrD   rI   rH   rK   c              	   C   sP  t | |d}|dkr2td| j d dS |d d }t| |d d}|dk	rdt| |di }|d}	t|d	 |d
}
|	dk	rzt|	}	W n( tt	fk
r   td|	 dY nX t
| ||	|
d nt| |
d |dk	r:t| t|d	 |}t j|t||d| jj | jjdd}t| t| j d dS )aw  
    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.
        headers (`dict`, *optional*):
            Headers to include in the request, including authentication and user agent headers.

    Raises:
        [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
            If `lfs_batch_action` is improperly formatted
        [`HTTPError`](https://requests.readthedocs.io/en/latest/api/#requests.HTTPError)
            If the upload resulted in an error
    actionsNzContent of file z. is already present upstream - skipping uploadrN   verifyheader
chunk_sizehref)rH   zTMalformed response from LFS batch endpoint: `chunk_size` should be an integer. Got 'z'.)rV   rs   rt   
upload_url)rV   rv   )rD   rI   rQ   rZ   z: Upload successful)r^   rd   loggerdebugpath_in_repo_validate_lfs_actionr   r@   rg   	TypeError_upload_multi_part_upload_single_partr   rc   r   upload_infor   rS   r    r   )rV   rp   rD   rI   rH   rq   upload_actionverify_actionrs   rt   rv   Z
verify_urlZverify_respr,   r,   r-   
lfs_upload   s@    





r   Z
lfs_actionc                 C   s:   t | dtr.| ddks6t | dts6td| S ).validates response from the LFS batch endpointru   rs   Nz"lfs_action is improperly formatted)re   rd   rB   dictrg   r   r,   r,   r-   rz     s    rz   )lfs_batch_actionsc                 C   sp   t | dtr t | dts(td| di d}| di d}|dk	r\t| |dk	rlt| | S )r   rR   r    z)lfs_batch_actions is improperly formattedrq   rN   rr   N)re   rd   rB   r@   rg   rz   )r   r   r   r,   r,   r-   r^     s     r^   )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   rR   r    z'lfs_batch_error is improperly formattedr]   messagecode)re   rd   rB   r@   rg   r   )r   
error_infor,   r,   r-   ra   '  s     
ra   )rV   rv   rK   c              	   C   s2   | j dd}td||d}t| W 5 Q R X dS )a  
    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:
     [`HTTPError`](https://requests.readthedocs.io/en/latest/api/#requests.HTTPError)
        If the upload resulted in an error.
    TZ	with_tqdmPUTr/   N)as_filer   r   )rV   rv   r4   responser,   r,   r-   r}   5  s    r}   )rV   rs   rt   rv   rK   c                 C   s   t || j|d}tj}tjrBt| jtsBt| jtsBt	d d}|rTt
| ||dnt| ||d}t j|t|| jj td}t| dS )z@
    Uploads file using HF multipart LFS transfer protocol.
    )rs   r~   rt   zlhf_transfer is enabled but does not support uploading from bytes or BinaryIO, falling back to regular uploadF)rV   sorted_parts_urlsrt   )r[   rI   N)_get_sorted_parts_urlsr~   r   ZHF_HUB_ENABLE_HF_TRANSFERre   path_or_fileobjrB   r   warningswarn_upload_parts_hf_transfer_upload_parts_iterativelyr   rc   _get_completion_payloadr   rS   rb   r   )rV   rs   rt   rv   r   Zuse_hf_transferresponse_headersZcompletion_resr,   r,   r-   r|   K  s,    

r|   )rs   r~   rt   rK   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,   )rT   _rv   r,   r,   r-   rU   o  s   z*_get_sorted_parts_urls.<locals>.<listcomp>c                 S   s2   g | ]*\}}|  rt|d krt|d|fqS )r   
   )isdigitr2   r@   )rT   Zpart_numrv   r,   r,   r-   rU   r  s    c                 S   s   | d S )Nr   r,   )tr,   r,   r-   <lambda>w      z(_get_sorted_parts_urls.<locals>.<lambda>)keyz0Invalid server response to upload large LFS file)sorteditemsr2   r   r    rg   )rs   r~   rt   Zsorted_part_upload_urlsZ	num_partsr,   r,   r-   r   n  s    r   )r   rR   rK   c                 C   sf   g }t | D ]N\}}|d}|d ks.|dkrFtd| d|d  ||d |d q||dS )Nrm   rL   zInvalid etag (`z`) returned for part r   )rl   rm   )rR   ro   )	enumeraterd   rg   append)r   rR   ro   Zpart_numberrs   rm   r,   r,   r-   r     s    
r   )rV   r   rt   rK   c           	      C   sr   g }| j ddX}t|D ]H\}}t||| |d(}td||d}t| ||j W 5 Q R X qW 5 Q R X |S )NTr   )Z	seek_fromZ
read_limitr   r/   )r   r   r   r   r   r   rI   )	rV   r   rt   rI   r4   Zpart_idxZpart_upload_urlZfileobj_sliceZpart_upload_resr,   r,   r-   r     s    "r   c           
      C   s   zddl m} W n tk
r,   tdY nX dt|jk}|sLtd | j	j
}| j}t|dkrxd|dd   }td	d
|d|tt dd}z0|f | j||dddd|rd|jini }W n, tk
r }	 ztd|	W 5 d }	~	X Y nX |s|| |W  5 Q R  S Q R X 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`.callbackzYou are using an outdated version of `hf_transfer`. Consider upgrading to latest version to enable progress bars using `pip install -U hf_transfer`.(   u   (…)iBTzhuggingface_hub.lfs_upload)unitZ
unit_scaletotalinitialdescdisablerX            )	file_pathZ
parts_urlsrt   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   ImportErrorrg   inspect	signature
parametersr   r   r~   r    ry   r2   r   r   rw   getEffectiveLevelr   update	ExceptionRuntimeError)
rV   r   rt   r   Zsupports_callbackr   r   progressoutputer,   r,   r-   r     sZ    


	
r   )NNNN)NNN)Dr=   r   r&   rer   Zdataclassesr   mathr   os.pathr   pathlibr   typingr   r   r   r	   r
   r   r   r   urllib.parser   Zhuggingface_hubr   utilsr   r   r   r   r   r   r   r   Z
utils._lfsr   Z	utils.shar   r   Z
utils.tqdmr   Z_commit_apir   Z
get_loggerr:   rw   compileZ	OID_REGEXZLFS_MULTIPART_UPLOAD_COMMANDrb   r   rB   r   rj   rk   rn   r   rz   r^   ra   r}   r@   r|   r   r   r   r   r,   r,   r,   r-   <module>   s   ((


)    
V
   F
#    