o
    gX                     @   s  U 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ZddlmZ ddl	m
Z
 ddlmZmZmZmZmZ ddlZddlmZ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& ddl'm(Z( ddl)m*Z* e$+e,Z-dZ.dZ/ej0dej1dZ2G dd deZ3G dd deZ4dej5fddZ6eg ej5f Z7e6a8e7e9d< e6fde7ddfdd Z:dej5fd!d"Z;dAd#d$Z<ed%e=d&e=dej5fd'd(Z>d)dd*ej?ej@fe
jAd+d,e*d-eBd.e=d/eCd0eCd1eeeD eeeD d2f f d3ee=ee=d2f f defd4d5ZEd-eBd6eeB deBfd7d8ZFdBd9ed:eeB ddfd;d<ZGd=ee! d>eBd9ede!fd?d@ZHdS )Cz>Contains utilities to handle HTTP requests in Huggingface Hub.    N)	lru_cache)
HTTPStatus)CallableOptionalTupleTypeUnion)	HTTPErrorResponse)HTTPAdapter)PreparedRequest)OfflineModeIsEnabled   )	constants)BadRequestErrorDisabledRepoErrorEntryNotFoundErrorGatedRepoErrorHfHubHTTPErrorRepositoryNotFoundErrorRevisionNotFoundError   )logging)JSONDecodeError)SliceFileObj)HTTP_METHOD_TX-Amzn-Trace-Idzx-request-ida  
        # staging or production endpoint
        ^https://[^/]+
        (
            # on /api/repo_type/repo_id
            /api/(models|datasets|spaces)/(.+)
            |
            # or /repo_id/resolve/revision/...
            /(.+)/resolve/(.+)
        )
    )flagsc                       s6   e Zd ZdZ fddZdedef fddZ  ZS )UniqueRequestIdAdapterr   c                    s   t  j|fi | t|jvr|jtptt |jt< t|jdd	d}t
d|jt  d|j d|j d| d	 d S )	Nauthorization z
Bearer hf_zRequest z:  z (authenticated: ))superadd_headersX_AMZN_TRACE_IDheadersgetX_REQUEST_IDstruuiduuid4
startswithloggerdebugmethodurl)selfrequestkwargs	has_token	__class__ R/var/www/visachat/venv/lib/python3.10/site-packages/huggingface_hub/utils/_http.pyr$   M   s   
&z"UniqueRequestIdAdapter.add_headersr2   returnc              
      sh   zt  j|g|R i |W S  tjy3 } z|jt}|dur.g |jd| dR |_ d}~ww )zSCatch any RequestException to append request id to the error message for debugging.Nz(Request ID: r"   )r#   sendrequestsRequestExceptionr&   r'   r%   args)r1   r2   r=   r3   e
request_idr5   r7   r8   r:   Z   s   zUniqueRequestIdAdapter.send)	__name__
__module____qualname__r%   r$   r   r
   r:   __classcell__r7   r7   r5   r8   r   J   s    r   c                   @   s   e Zd ZdedefddZdS )OfflineAdapterr2   r9   c                 O   s   t d|j d)NzCannot reach za: offline mode is enabled. To disable it, please unset the `HF_HUB_OFFLINE` environment variable.)r   r0   )r1   r2   r=   r3   r7   r7   r8   r:   g   s   zOfflineAdapter.sendN)r@   rA   rB   r   r
   r:   r7   r7   r7   r8   rD   f   s    rD   r9   c                  C   sN   t  } tjr| dt  | dt  | S | dt  | dt  | S )Nzhttp://zhttps://)r;   Sessionr   HF_HUB_OFFLINEmountrD   r   )sessionr7   r7   r8   _default_backend_factorym   s   rI   _GLOBAL_BACKEND_FACTORYbackend_factoryc                 C   s   | a t  dS )a  
    Configure the HTTP backend by providing a `backend_factory`. Any HTTP calls made by `huggingface_hub` will use a
    Session object instantiated by this factory. This can be useful if you are running your scripts in a specific
    environment requiring custom configuration (e.g. custom proxy or certifications).

    Use [`get_session`] to get a configured Session. Since `requests.Session` is not guaranteed to be thread-safe,
    `huggingface_hub` creates 1 Session instance per thread. They are all instantiated using the same `backend_factory`
    set in [`configure_http_backend`]. A LRU cache is used to cache the created sessions (and connections) between
    calls. Max size is 128 to avoid memory leaks if thousands of threads are spawned.

    See [this issue](https://github.com/psf/requests/issues/2766) to know more about thread-safety in `requests`.

    Example:
    ```py
    import requests
    from huggingface_hub import configure_http_backend, get_session

    # Create a factory function that returns a Session with configured proxies
    def backend_factory() -> requests.Session:
        session = requests.Session()
        session.proxies = {"http": "http://10.10.1.10:3128", "https": "https://10.10.1.11:1080"}
        return session

    # Set it as the default session factory
    configure_http_backend(backend_factory=backend_factory)

    # In practice, this is mostly done internally in `huggingface_hub`
    session = get_session()
    ```
    N)rJ   reset_sessions)rK   r7   r7   r8   configure_http_backend|   s    
rM   c                   C   s   t t t dS )a  
    Get a `requests.Session` object, using the session factory from the user.

    Use [`get_session`] to get a configured Session. Since `requests.Session` is not guaranteed to be thread-safe,
    `huggingface_hub` creates 1 Session instance per thread. They are all instantiated using the same `backend_factory`
    set in [`configure_http_backend`]. A LRU cache is used to cache the created sessions (and connections) between
    calls. Max size is 128 to avoid memory leaks if thousands of threads are spawned.

    See [this issue](https://github.com/psf/requests/issues/2766) to know more about thread-safety in `requests`.

    Example:
    ```py
    import requests
    from huggingface_hub import configure_http_backend, get_session

    # Create a factory function that returns a Session with configured proxies
    def backend_factory() -> requests.Session:
        session = requests.Session()
        session.proxies = {"http": "http://10.10.1.10:3128", "https": "https://10.10.1.11:1080"}
        return session

    # Set it as the default session factory
    configure_http_backend(backend_factory=backend_factory)

    # In practice, this is mostly done internally in `huggingface_hub`
    session = get_session()
    ```
    
process_id	thread_id)_get_session_from_cacheosgetpid	threading	get_identr7   r7   r7   r8   get_session   s   rV   c                   C   s   t   dS )zReset the cache of sessions.

    Mostly used internally when sessions are reconfigured or an SSLError is raised.
    See [`configure_http_backend`] for more details.
    N)rQ   cache_clearr7   r7   r7   r8   rL      s   rL   rO   rP   c                 C   s   t  S )z
    Create a new session per thread using global factory. Using LRU cache (maxsize 128) to avoid memory leaks when
    using thousands of threads. Cache is cleared when `configure_http_backend` is called.
    )rJ   rN   r7   r7   r8   rQ      s   rQ         )max_retriesbase_wait_timemax_wait_timeretry_on_exceptionsretry_on_status_codesr/   r0   rZ   r[   r\   r]   .r^   c                K   sp  t |tr|f}t |tr|f}d}|}	d}
d|v r*t |d tjtfr*|d  }
t }	 |d7 }z:|
dur>|d |
 |j	d| |d|}|j
|vrQ|W S td|j
 d|  d	|  ||krk|  |W S W n/ |y } z#td
| d|  d	|  t |tjrt  ||kr|W Y d}~nd}~ww td|	 d| d| d t|	 t||	d }	q.)a#  Wrapper around requests to retry calls on an endpoint, with exponential backoff.

    Endpoint call is retried on exceptions (ex: connection timeout, proxy error,...)
    and/or on specific status codes (ex: service unavailable). If the call failed more
    than `max_retries`, the exception is thrown or `raise_for_status` is called on the
    response object.

    Re-implement mechanisms from the `backoff` library to avoid adding an external
    dependencies to `hugging_face_hub`. See https://github.com/litl/backoff.

    Args:
        method (`Literal["GET", "OPTIONS", "HEAD", "POST", "PUT", "PATCH", "DELETE"]`):
            HTTP method to perform.
        url (`str`):
            The URL of the resource to fetch.
        max_retries (`int`, *optional*, defaults to `5`):
            Maximum number of retries, defaults to 5 (no retries).
        base_wait_time (`float`, *optional*, defaults to `1`):
            Duration (in seconds) to wait before retrying the first time.
            Wait time between retries then grows exponentially, capped by
            `max_wait_time`.
        max_wait_time (`float`, *optional*, defaults to `8`):
            Maximum duration (in seconds) to wait before retrying.
        retry_on_exceptions (`Type[Exception]` or `Tuple[Type[Exception]]`, *optional*):
            Define which exceptions must be caught to retry the request. Can be a single type or a tuple of types.
            By default, retry on `requests.Timeout` and `requests.ConnectionError`.
        retry_on_status_codes (`int` or `Tuple[int]`, *optional*, defaults to `503`):
            Define on which status codes the request must be retried. By default, only
            HTTP 503 Service Unavailable is retried.
        **kwargs (`dict`, *optional*):
            kwargs to pass to `requests.request`.

    Example:
    ```
    >>> from huggingface_hub.utils import http_backoff

    # Same usage as "requests.request".
    >>> response = http_backoff("GET", "https://www.google.com")
    >>> response.raise_for_status()

    # If you expect a Gateway Timeout from time to time
    >>> http_backoff("PUT", upload_url, data=data, retry_on_status_codes=504)
    >>> response.raise_for_status()
    ```

    <Tip warning={true}>

    When using `requests` it is possible to stream data by passing an iterator to the
    `data` argument. On http backoff this is a problem as the iterator is not reset
    after a failed call. This issue is mitigated for file objects or any IO streams
    by saving the initial position of the cursor (with `data.tell()`) and resetting the
    cursor between each call (with `data.seek()`). For arbitrary iterators, http backoff
    will fail. If this is a hard constraint for you, please let us know by opening an
    issue on [Github](https://github.com/huggingface/huggingface_hub).

    </Tip>
    r   NdataTr   )r/   r0   zHTTP Error z thrown while requesting r!   'z' thrown while requesting zRetrying in z	s [Retry /z].r   r7   )
isinstancetypeintioIOBaser   tellrV   seekr2   status_coder-   warningraise_for_statusr;   ConnectionErrorrL   timesleepmin)r/   r0   rZ   r[   r\   r]   r^   r3   nb_tries
sleep_timeio_obj_initial_posrH   responseerrr7   r7   r8   http_backoff   sH   
G



ru   endpointc                 C   sD   |r| dntj}|tjtjfvr | tj|} | tj|} | S )zReplace the default endpoint in a URL by a custom one.

    This is useful when using a proxy and the Hugging Face Hub returns a URL with the default endpoint.
    ra   )rstripr   ENDPOINT_HF_DEFAULT_ENDPOINT_HF_DEFAULT_STAGING_ENDPOINTreplace)r0   rv   r7   r7   r8   fix_hf_endpoint_in_urlP  s
   r|   rs   endpoint_namec              
   C   sL  z|    W dS  ty% } z| jd}| jd}|dkr7| j dd d| j d }tt|| ||dkrQ| j dd d	| j d }tt|| ||d
krk| j dd d| j d }tt	|| ||dkr| j dd d| j d d d }tt
|| ||dks| jdkr| jdur| jjdurt| jjdur| j dd d| j d d }tt|| || jdkr|durd| dnd}tt|| || jdkrd| j d| dd| j d d }tt|| || jdkr| jjd}| d| d| jd  d}tt|| |ttt|| |d}~ww )!a  
    Internal version of `response.raise_for_status()` that will refine a
    potential HTTPError. Raised exception will be an instance of `HfHubHTTPError`.

    This helper is meant to be the unique method to raise_for_status when making a call
    to the Hugging Face Hub.


    Example:
    ```py
        import requests
        from huggingface_hub.utils import get_session, hf_raise_for_status, HfHubHTTPError

        response = get_session().post(...)
        try:
            hf_raise_for_status(response)
        except HfHubHTTPError as e:
            print(str(e)) # formatted message
            e.request_id, e.server_message # details returned by server

            # Complete the error message with additional information once it's raised
            e.append_to_message("
`create_commit` expects the repository to exist.")
            raise
    ```

    Args:
        response (`Response`):
            Response from the server.
        endpoint_name (`str`, *optional*):
            Name of the endpoint that has been called. If provided, the error message
            will be more complete.

    <Tip warning={true}>

    Raises when the request has failed:

        - [`~utils.RepositoryNotFoundError`]
            If the repository to download from cannot be found. This may be because it
            doesn't exist, because `repo_type` is not set correctly, or because the repo
            is `private` and you do not have access.
        - [`~utils.GatedRepoError`]
            If the repository exists but is gated and the user is not on the authorized
            list.
        - [`~utils.RevisionNotFoundError`]
            If the repository exists but the revision couldn't be find.
        - [`~utils.EntryNotFoundError`]
            If the repository exists but the entry (e.g. the requested file) couldn't be
            find.
        - [`~utils.BadRequestError`]
            If request failed with a HTTP 400 BadRequest error.
        - [`~utils.HfHubHTTPError`]
            If request failed for a reason not listed above.

    </Tip>
    zX-Error-CodeX-Error-MessageRevisionNotFoundz Client Error.

zRevision Not Found for url: .EntryNotFoundzEntry Not Found for url: 	GatedRepoz!Cannot access gated repo for url z$Access to this resource is disabled.z!Cannot access repository for url 
RepoNotFoundi  NzRepository Not Found for url: z
Please make sure you specified the correct `repo_id` and `repo_type`.
If you are trying to access a private or gated repo, make sure you are authenticated.i  z

Bad request for z
 endpoint:z

Bad request:i  z Forbidden: z
Cannot access content at: z2
Make sure your token has the correct permissions.i  Rangez. Requested range: z. Content-Range: zContent-Range)rk   r	   r&   r'   ri   r0   _formatr   r   r   r   r2   REPO_API_REGEXsearchr   r   r   r)   )rs   r}   r>   
error_codeerror_messagemessagerange_headerr7   r7   r8   hf_raise_for_status]  sx   8





r   
error_typecustom_messagec                 C   s  g }|j d}|d ur|| z8| }|d}|d ur/t|tr*|| n|| |d}|d urH|D ]}d|v rG||d  q:W n tyh   |j dd}|jrfd|	 vrf||j Y nw dd	 |D }tt
|}d
|}	|}
|	r|		 |	 vrd|v r|
d
|	 7 }
n|
d|	 7 }
t|j td}|rd| d}nt|j td}|rd| d}|r|	 |
	 vrd
|
v r|
d
}|
d | | |
|d   }
n|
|7 }
| |
 ||	pd dS )Nr~   errorerrorsr   zContent-Typer    htmlc                 S   s$   g | ]}t | rt | qS r7   )r)   strip).0liner7   r7   r8   
<listcomp>  s   $ z_format.<locals>.<listcomp>r   r   z (Request ID: r"   z (Amzn Trace ID: )rs   server_message)r&   r'   appendjsonrb   listextendr   textlowerdictfromkeysjoinr)   r(   r%   indexr   )r   r   rs   server_errorsfrom_headersr_   r   r   content_typer   final_error_messager?   request_id_messagenewline_indexr7   r7   r8   r     sX   






r   )r9   N)N)I__doc__re   rR   rerT   rm   r*   	functoolsr   httpr   typingr   r   r   r   r   r;   r	   r
   requests.adaptersr   requests.modelsr   huggingface_hub.errorsr   r    r   r   r   r   r   r   r   r   r   r   _fixesr   _lfsr   _typingr   
get_loggerr@   r-   r%   r(   compileVERBOSEr   r   rD   rE   rI   BACKEND_FACTORY_TrJ   __annotations__rM   rV   rL   rd   rQ   Timeoutrl   SERVICE_UNAVAILABLEr)   float	Exceptionru   r|   r   r   r7   r7   r7   r8   <module>   s   $	
$
 	
~ "